From 07233324cc95f75e91ab901275aba45bcceff2db Mon Sep 17 00:00:00 2001 From: haoxr <1490493387@qq.com> Date: Sat, 30 Jan 2021 00:40:26 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=BC=94=E7=A4=BA=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E7=A6=81=E6=AD=A2=E5=88=A0=E9=99=A4=E5=92=8C=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- youlai-auth/pom.xml | 11 +---- .../common/core/constant/AuthConstants.java | 2 + .../youlai/common/core/result/ResultCode.java | 6 ++- youlai-gateway/pom.xml | 1 - .../gateway/config/ResourceServerConfig.java | 23 ++-------- .../gateway/filter/AuthGlobalFilter.java | 44 ++++++++++++------- .../com/youlai/gateway/util/WebUtils.java | 25 +++++++++++ 7 files changed, 65 insertions(+), 47 deletions(-) diff --git a/youlai-auth/pom.xml b/youlai-auth/pom.xml index a8128f267..4923411a3 100644 --- a/youlai-auth/pom.xml +++ b/youlai-auth/pom.xml @@ -68,7 +68,6 @@ ${youlai.version} - com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery @@ -98,12 +97,6 @@ spring-boot-configuration-processor - - org.springframework.boot - spring-boot-starter-actuator - - - org.springframework.cloud @@ -154,13 +147,13 @@ 1.0.0 - + diff --git a/youlai-common/common-core/src/main/java/com/youlai/common/core/constant/AuthConstants.java b/youlai-common/common-core/src/main/java/com/youlai/common/core/constant/AuthConstants.java index c3e9ab03a..c24006fd0 100644 --- a/youlai-common/common-core/src/main/java/com/youlai/common/core/constant/AuthConstants.java +++ b/youlai-common/common-core/src/main/java/com/youlai/common/core/constant/AuthConstants.java @@ -49,6 +49,8 @@ public interface AuthConstants { String JWT_CLIENT_ID_KEY = "client_id"; + String JWT_JTI_KEY = "client_id"; + /** * JWT存储权限前缀 */ diff --git a/youlai-common/common-core/src/main/java/com/youlai/common/core/result/ResultCode.java b/youlai-common/common-core/src/main/java/com/youlai/common/core/result/ResultCode.java index bda12bcf2..ebd0fc9d8 100644 --- a/youlai-common/common-core/src/main/java/com/youlai/common/core/result/ResultCode.java +++ b/youlai-common/common-core/src/main/java/com/youlai/common/core/result/ResultCode.java @@ -27,8 +27,10 @@ public enum ResultCode implements IResultCode, Serializable { CLIENT_AUTHENTICATION_FAILED("A0212","客户端认证失败"), // * TOKEN_INVALID_OR_EXPIRED("A0230","token无效或已过期"), - USER_AUTHORIZED_ERROR ("A0300","访问权限异常"), - USER_ACCESS_UNAUTHORIZED ("A0301","访问未授权"), + AUTHORIZED_ERROR ("A0300","访问权限异常"), + ACCESS_UNAUTHORIZED ("A0301","访问未授权"), + FORBIDDEN_OPERATION ("A0302","演示环境禁止修改、删除重要数据,请本地部署后测试"), + USER_REQUEST_PARAM_ERROR("A0400","用户请求参数错误"), USER_REQUEST_PARAM_IS_BLANK("A0410","请求必填参数为空"), diff --git a/youlai-gateway/pom.xml b/youlai-gateway/pom.xml index 9b06db924..9cfc4e8b9 100644 --- a/youlai-gateway/pom.xml +++ b/youlai-gateway/pom.xml @@ -68,7 +68,6 @@ ${youlai.version} - org.springframework.cloud spring-cloud-starter-loadbalancer diff --git a/youlai-gateway/src/main/java/com/youlai/gateway/config/ResourceServerConfig.java b/youlai-gateway/src/main/java/com/youlai/gateway/config/ResourceServerConfig.java index d6bca0d4c..5783543de 100644 --- a/youlai-gateway/src/main/java/com/youlai/gateway/config/ResourceServerConfig.java +++ b/youlai-gateway/src/main/java/com/youlai/gateway/config/ResourceServerConfig.java @@ -6,6 +6,7 @@ import com.youlai.common.core.constant.AuthConstants; import com.youlai.common.core.result.Result; import com.youlai.common.core.result.ResultCode; import com.youlai.gateway.security.AuthorizationManager; +import com.youlai.gateway.util.WebUtils; import lombok.AllArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -66,16 +67,7 @@ public class ResourceServerConfig { ServerAccessDeniedHandler accessDeniedHandler() { return (exchange, denied) -> { Mono mono = Mono.defer(() -> Mono.just(exchange.getResponse())) - .flatMap(response -> { - response.setStatusCode(HttpStatus.OK); - response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); - response.getHeaders().set("Access-Control-Allow-Origin", "*"); - response.getHeaders().set("Cache-Control", "no-cache"); - String body = JSONUtil.toJsonStr(Result.failed(ResultCode.USER_ACCESS_UNAUTHORIZED)); - DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8"))); - return response.writeWith(Mono.just(buffer)) - .doOnError(error -> DataBufferUtils.release(buffer)); - }); + .flatMap(response ->WebUtils.writeFailedToResponse(response,ResultCode.ACCESS_UNAUTHORIZED)); return mono; }; @@ -88,16 +80,7 @@ public class ResourceServerConfig { ServerAuthenticationEntryPoint authenticationEntryPoint() { return (exchange, e) -> { Mono mono = Mono.defer(() -> Mono.just(exchange.getResponse())) - .flatMap(response -> { - response.setStatusCode(HttpStatus.OK); - response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); - response.getHeaders().set("Access-Control-Allow-Origin", "*"); - response.getHeaders().set("Cache-Control", "no-cache"); - String body = JSONUtil.toJsonStr(Result.failed(ResultCode.TOKEN_INVALID_OR_EXPIRED)); - DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8"))); - return response.writeWith(Mono.just(buffer)) - .doOnError(error -> DataBufferUtils.release(buffer)); - }); + .flatMap(response -> WebUtils.writeFailedToResponse(response,ResultCode.TOKEN_INVALID_OR_EXPIRED)); return mono; }; } diff --git a/youlai-gateway/src/main/java/com/youlai/gateway/filter/AuthGlobalFilter.java b/youlai-gateway/src/main/java/com/youlai/gateway/filter/AuthGlobalFilter.java index a3e511e43..242e4645f 100644 --- a/youlai-gateway/src/main/java/com/youlai/gateway/filter/AuthGlobalFilter.java +++ b/youlai-gateway/src/main/java/com/youlai/gateway/filter/AuthGlobalFilter.java @@ -7,16 +7,20 @@ import com.nimbusds.jose.JWSObject; import com.youlai.common.core.constant.AuthConstants; import com.youlai.common.core.result.Result; import com.youlai.common.core.result.ResultCode; +import com.youlai.gateway.util.WebUtils; import lombok.AllArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.logging.log4j.util.Strings; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; 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.data.redis.core.RedisTemplate; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; @@ -28,43 +32,53 @@ import reactor.core.publisher.Mono; import java.nio.charset.Charset; /** - * 黑名单token过滤器 + * 全局过滤器 */ @Component @Slf4j -@AllArgsConstructor public class AuthGlobalFilter implements GlobalFilter, Ordered { + @Autowired private RedisTemplate redisTemplate; + // 是否演示环境 + @Value("${demo}") + private Boolean isDemoEnvironment; + @SneakyThrows @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + + ServerHttpRequest request = exchange.getRequest(); + ServerHttpResponse response = exchange.getResponse(); + + // 演示环境禁止删除和修改 + if (isDemoEnvironment && (HttpMethod.PUT.toString().equals(request.getMethodValue()) || + HttpMethod.DELETE.toString().equals(request.getMethodValue()) + )) { + log.warn(ResultCode.FORBIDDEN_OPERATION.getMsg()); + return WebUtils.writeFailedToResponse(response, ResultCode.FORBIDDEN_OPERATION); + } + + // 无token放行 String token = exchange.getRequest().getHeaders().getFirst(AuthConstants.JWT_TOKEN_HEADER); if (StrUtil.isBlank(token)) { return chain.filter(exchange); } + + // 解析JWT获取jti,以jti为key判断redis的黑名单列表是否存在,存在拦截响应token失效 token = token.replace(AuthConstants.JWT_TOKEN_PREFIX, Strings.EMPTY); JWSObject jwsObject = JWSObject.parse(token); String payload = jwsObject.getPayload().toString(); - - // 黑名单token(登出、修改密码)校验 JSONObject jsonObject = JSONUtil.parseObj(payload); - String jti = jsonObject.getStr("jti"); // JWT唯一标识 - + String jti = jsonObject.getStr(AuthConstants.JWT_JTI_KEY); Boolean isBlack = redisTemplate.hasKey(AuthConstants.TOKEN_BLACKLIST_PREFIX + jti); if (isBlack) { - ServerHttpResponse response = exchange.getResponse(); - response.setStatusCode(HttpStatus.OK); - response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); - response.getHeaders().set("Access-Control-Allow-Origin", "*"); - response.getHeaders().set("Cache-Control", "no-cache"); - String body = JSONUtil.toJsonStr(Result.failed(ResultCode.TOKEN_INVALID_OR_EXPIRED)); - DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8"))); - return response.writeWith(Mono.just(buffer)); + return WebUtils.writeFailedToResponse(response, ResultCode.TOKEN_INVALID_OR_EXPIRED); } - ServerHttpRequest request = exchange.getRequest().mutate() + // 存在token且不是黑名单,request写入JWT的载体信息 + request = exchange.getRequest().mutate() .header(AuthConstants.JWT_PAYLOAD_KEY, payload) .build(); exchange = exchange.mutate().request(request).build(); diff --git a/youlai-gateway/src/main/java/com/youlai/gateway/util/WebUtils.java b/youlai-gateway/src/main/java/com/youlai/gateway/util/WebUtils.java index 6d3a7eec5..2d6cbcb02 100644 --- a/youlai-gateway/src/main/java/com/youlai/gateway/util/WebUtils.java +++ b/youlai-gateway/src/main/java/com/youlai/gateway/util/WebUtils.java @@ -1,9 +1,34 @@ package com.youlai.gateway.util; +import cn.hutool.json.JSONUtil; +import com.youlai.common.core.result.Result; +import com.youlai.common.core.result.ResultCode; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.server.reactive.ServerHttpResponse; +import reactor.core.publisher.Mono; + +import java.nio.charset.Charset; + /** * @Author haoxr * @Date 2021-01-29 13:30 * @Version 1.0.0 */ public class WebUtils { + + public static Mono writeFailedToResponse(ServerHttpResponse response,ResultCode resultCode){ + response.setStatusCode(HttpStatus.OK); + response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + response.getHeaders().set("Access-Control-Allow-Origin", "*"); + response.getHeaders().set("Cache-Control", "no-cache"); + String body = JSONUtil.toJsonStr(Result.failed(resultCode)); + DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8"))); + return response.writeWith(Mono.just(buffer)) + .doOnError(error -> DataBufferUtils.release(buffer)); + } + }