19 changed files with 302 additions and 220 deletions
@ -0,0 +1,98 @@
|
||||
/* |
||||
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are met: |
||||
* |
||||
* Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
* Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* Neither the name of the dreamlu.net developer nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* Author: Chill 庄骞 (smallchill@163.com) |
||||
*/ |
||||
package org.springblade.gateway.filter; |
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException; |
||||
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
import io.jsonwebtoken.Claims; |
||||
import lombok.AllArgsConstructor; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.apache.commons.lang3.StringUtils; |
||||
import org.springblade.core.jwt.JwtUtil; |
||||
import org.springblade.gateway.props.AuthProperties; |
||||
import org.springblade.gateway.provider.AuthProvider; |
||||
import org.springblade.gateway.provider.ResponseProvider; |
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain; |
||||
import org.springframework.cloud.gateway.filter.GlobalFilter; |
||||
import org.springframework.core.Ordered; |
||||
import org.springframework.core.io.buffer.DataBuffer; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.server.reactive.ServerHttpResponse; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.web.server.ServerWebExchange; |
||||
import reactor.core.publisher.Flux; |
||||
import reactor.core.publisher.Mono; |
||||
|
||||
import java.nio.charset.StandardCharsets; |
||||
|
||||
/** |
||||
* 鉴权认证 |
||||
* |
||||
* @author Chill |
||||
*/ |
||||
@Slf4j |
||||
@Component |
||||
@AllArgsConstructor |
||||
public class AuthFilter implements GlobalFilter, Ordered { |
||||
private AuthProperties authProperties; |
||||
private ObjectMapper objectMapper; |
||||
|
||||
@Override |
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { |
||||
String path = exchange.getRequest().getURI().getPath(); |
||||
if (isSkip(path)) { |
||||
return chain.filter(exchange); |
||||
} |
||||
ServerHttpResponse resp = exchange.getResponse(); |
||||
String headerToken = exchange.getRequest().getHeaders().getFirst(AuthProvider.AUTH_KEY); |
||||
String paramToken = exchange.getRequest().getQueryParams().getFirst(AuthProvider.AUTH_KEY); |
||||
if (StringUtils.isAllBlank(headerToken, paramToken)) { |
||||
return unAuth(resp, "缺失令牌,鉴权失败"); |
||||
} |
||||
String auth = StringUtils.isBlank(headerToken) ? paramToken : headerToken; |
||||
String token = JwtUtil.getToken(auth); |
||||
Claims claims = JwtUtil.parseJWT(token); |
||||
if (claims == null) { |
||||
return unAuth(resp, "请求未授权"); |
||||
} |
||||
return chain.filter(exchange); |
||||
} |
||||
|
||||
private boolean isSkip(String path) { |
||||
return AuthProvider.getDefaultSkipUrl().stream().map(url -> url.replace(AuthProvider.TARGET, AuthProvider.REPLACEMENT)).anyMatch(path::startsWith) |
||||
|| authProperties.getSkipUrl().stream().map(url -> url.replace(AuthProvider.TARGET, AuthProvider.REPLACEMENT)).anyMatch(path::startsWith); |
||||
} |
||||
|
||||
private Mono<Void> unAuth(ServerHttpResponse resp, String msg) { |
||||
resp.setStatusCode(HttpStatus.UNAUTHORIZED); |
||||
resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8"); |
||||
String result = ""; |
||||
try { |
||||
result = objectMapper.writeValueAsString(ResponseProvider.unAuth(msg)); |
||||
} catch (JsonProcessingException e) { |
||||
log.error(e.getMessage(), e); |
||||
} |
||||
DataBuffer buffer = resp.bufferFactory().wrap(result.getBytes(StandardCharsets.UTF_8)); |
||||
return resp.writeWith(Flux.just(buffer)); |
||||
} |
||||
|
||||
@Override |
||||
public int getOrder() { |
||||
return -100; |
||||
} |
||||
|
||||
} |
@ -1,44 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are met: |
||||
* |
||||
* Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
* Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* Neither the name of the dreamlu.net developer nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* Author: Chill 庄骞 (smallchill@163.com) |
||||
*/ |
||||
|
||||
package org.springblade.gateway.handler; |
||||
|
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.MediaType; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.web.reactive.function.BodyInserters; |
||||
import org.springframework.web.reactive.function.server.HandlerFunction; |
||||
import org.springframework.web.reactive.function.server.ServerRequest; |
||||
import org.springframework.web.reactive.function.server.ServerResponse; |
||||
import reactor.core.publisher.Mono; |
||||
|
||||
/** |
||||
* Hystrix 降级处理 |
||||
* |
||||
* @author lengleng |
||||
*/ |
||||
@Slf4j |
||||
@Component |
||||
public class HystrixFallbackHandler implements HandlerFunction<ServerResponse> { |
||||
@Override |
||||
public Mono<ServerResponse> handle(ServerRequest serverRequest) { |
||||
log.error("网关执行请求:{}失败,hystrix服务降级处理", serverRequest.uri()); |
||||
return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR.value()) |
||||
.contentType(MediaType.TEXT_PLAIN).body(BodyInserters.fromObject("服务异常")); |
||||
} |
||||
} |
@ -1,60 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are met: |
||||
* |
||||
* Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
* Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* Neither the name of the dreamlu.net developer nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* Author: Chill 庄骞 (smallchill@163.com) |
||||
*/ |
||||
|
||||
package org.springblade.gateway.handler; |
||||
|
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.MediaType; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.web.reactive.function.BodyInserters; |
||||
import org.springframework.web.reactive.function.server.HandlerFunction; |
||||
import org.springframework.web.reactive.function.server.ServerRequest; |
||||
import org.springframework.web.reactive.function.server.ServerResponse; |
||||
import reactor.core.publisher.Mono; |
||||
import springfox.documentation.swagger.web.SecurityConfiguration; |
||||
import springfox.documentation.swagger.web.SecurityConfigurationBuilder; |
||||
|
||||
import java.util.Optional; |
||||
|
||||
/** |
||||
* SwaggerSecurityHandler |
||||
* |
||||
* @author lengleng |
||||
*/ |
||||
@Slf4j |
||||
@Component |
||||
public class SwaggerSecurityHandler implements HandlerFunction<ServerResponse> { |
||||
@Autowired(required = false) |
||||
private SecurityConfiguration securityConfiguration; |
||||
|
||||
/** |
||||
* Handle the given request. |
||||
* |
||||
* @param request the request to handler |
||||
* @return the response |
||||
*/ |
||||
@Override |
||||
public Mono<ServerResponse> handle(ServerRequest request) { |
||||
return ServerResponse.status(HttpStatus.OK) |
||||
.contentType(MediaType.APPLICATION_JSON_UTF8) |
||||
.body(BodyInserters.fromObject( |
||||
Optional.ofNullable(securityConfiguration) |
||||
.orElse(SecurityConfigurationBuilder.builder().build()))); |
||||
} |
||||
} |
@ -1,60 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are met: |
||||
* |
||||
* Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
* Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* Neither the name of the dreamlu.net developer nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* Author: Chill 庄骞 (smallchill@163.com) |
||||
*/ |
||||
|
||||
package org.springblade.gateway.handler; |
||||
|
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.MediaType; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.web.reactive.function.BodyInserters; |
||||
import org.springframework.web.reactive.function.server.HandlerFunction; |
||||
import org.springframework.web.reactive.function.server.ServerRequest; |
||||
import org.springframework.web.reactive.function.server.ServerResponse; |
||||
import reactor.core.publisher.Mono; |
||||
import springfox.documentation.swagger.web.UiConfiguration; |
||||
import springfox.documentation.swagger.web.UiConfigurationBuilder; |
||||
|
||||
import java.util.Optional; |
||||
|
||||
/** |
||||
* SwaggerUiHandler |
||||
* |
||||
* @author lengleng |
||||
*/ |
||||
@Slf4j |
||||
@Component |
||||
public class SwaggerUiHandler implements HandlerFunction<ServerResponse> { |
||||
@Autowired(required = false) |
||||
private UiConfiguration uiConfiguration; |
||||
|
||||
/** |
||||
* Handle the given request. |
||||
* |
||||
* @param request the request to handler |
||||
* @return the response |
||||
*/ |
||||
@Override |
||||
public Mono<ServerResponse> handle(ServerRequest request) { |
||||
return ServerResponse.status(HttpStatus.OK) |
||||
.contentType(MediaType.APPLICATION_JSON_UTF8) |
||||
.body(BodyInserters.fromObject( |
||||
Optional.ofNullable(uiConfiguration) |
||||
.orElse(UiConfigurationBuilder.builder().build()))); |
||||
} |
||||
} |
@ -0,0 +1,60 @@
|
||||
/* |
||||
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are met: |
||||
* |
||||
* Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
* Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* Neither the name of the dreamlu.net developer nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* Author: Chill 庄骞 (smallchill@163.com) |
||||
*/ |
||||
package org.springblade.gateway.provider; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* 鉴权配置 |
||||
* |
||||
* @author Chill |
||||
*/ |
||||
public class AuthProvider { |
||||
|
||||
public static String TARGET = "/**"; |
||||
public static String REPLACEMENT = ""; |
||||
public static String AUTH_KEY = "Blade-Auth"; |
||||
private static List<String> defaultSkipUrl = new ArrayList<>(); |
||||
|
||||
static { |
||||
defaultSkipUrl.add("/client/**"); |
||||
defaultSkipUrl.add("/oauth/token/**"); |
||||
defaultSkipUrl.add("/token/**"); |
||||
defaultSkipUrl.add("/actuator/health/**"); |
||||
defaultSkipUrl.add("/v2/api-docs/**"); |
||||
defaultSkipUrl.add("/v2/api-docs-ext/**"); |
||||
defaultSkipUrl.add("/auth/**"); |
||||
defaultSkipUrl.add("/log/**"); |
||||
defaultSkipUrl.add("/menu/routes"); |
||||
defaultSkipUrl.add("/menu/auth-routes"); |
||||
defaultSkipUrl.add("/menu/top-menu"); |
||||
defaultSkipUrl.add("/process/resource-view"); |
||||
defaultSkipUrl.add("/process/diagram-view"); |
||||
defaultSkipUrl.add("/manager/check-upload"); |
||||
defaultSkipUrl.add("/error/**"); |
||||
defaultSkipUrl.add("/assets/**"); |
||||
} |
||||
|
||||
/** |
||||
* 默认无需鉴权的API |
||||
*/ |
||||
public static List<String> getDefaultSkipUrl() { |
||||
return defaultSkipUrl; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,84 @@
|
||||
/* |
||||
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are met: |
||||
* |
||||
* Redistributions of source code must retain the above copyright notice, |
||||
* this list of conditions and the following disclaimer. |
||||
* Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* Neither the name of the dreamlu.net developer nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* Author: Chill 庄骞 (smallchill@163.com) |
||||
*/ |
||||
package org.springblade.gateway.provider; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* 请求响应返回 |
||||
* |
||||
* @author Chill |
||||
*/ |
||||
public class ResponseProvider { |
||||
|
||||
/** |
||||
* 成功 |
||||
* |
||||
* @param message 信息 |
||||
* @return |
||||
*/ |
||||
public static Map<String, Object> success(String message) { |
||||
return response(200, message); |
||||
} |
||||
|
||||
/** |
||||
* 失败 |
||||
* |
||||
* @param message 信息 |
||||
* @return |
||||
*/ |
||||
public static Map<String, Object> fail(String message) { |
||||
return response(400, message); |
||||
} |
||||
|
||||
/** |
||||
* 未授权 |
||||
* |
||||
* @param message 信息 |
||||
* @return |
||||
*/ |
||||
public static Map<String, Object> unAuth(String message) { |
||||
return response(401, message); |
||||
} |
||||
|
||||
/** |
||||
* 服务器异常 |
||||
* |
||||
* @param message 信息 |
||||
* @return |
||||
*/ |
||||
public static Map<String, Object> error(String message) { |
||||
return response(500, message); |
||||
} |
||||
|
||||
/** |
||||
* 构建返回的JSON数据格式 |
||||
* |
||||
* @param status 状态码 |
||||
* @param message 信息 |
||||
* @return |
||||
*/ |
||||
public static Map<String, Object> response(int status, String message) { |
||||
Map<String, Object> map = new HashMap<>(16); |
||||
map.put("code", status); |
||||
map.put("message", message); |
||||
map.put("data", null); |
||||
return map; |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue