From da7a012d7d6cfcdf02d96279224656f0744590cb Mon Sep 17 00:00:00 2001 From: haoxr <1490493387@qq.com> Date: Sun, 27 Sep 2020 00:38:55 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E9=80=80=E5=87=BA=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0JWT=E8=87=B3=E9=BB=91=E5=90=8D=E5=8D=95?= =?UTF-8?q?=E5=A4=B1=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/OAuth2ExceptionSerializer.java | 1 - .../OAuth2WebResponseExceptionTranslator.java | 6 +-- .../auth/controller/AuthController.java | 37 ++++++++------- .../component/AuthorizationManager.java | 1 - .../CustomServerAccessDeniedHandler.java | 4 +- .../CustomServerAuthenticationEntryPoint.java | 4 +- .../gateway/config/ResourceServerConfig.java | 2 - .../gateway/filter/AuthGlobalFilter.java | 38 +++++++++++++-- .../filter/WhiteListRemoveJwtFilter.java | 47 ------------------- 9 files changed, 62 insertions(+), 78 deletions(-) delete mode 100644 youlai-gateway/src/main/java/com/youlai/gateway/filter/WhiteListRemoveJwtFilter.java diff --git a/youlai-auth/src/main/java/com/youlai/auth/component/OAuth2ExceptionSerializer.java b/youlai-auth/src/main/java/com/youlai/auth/component/OAuth2ExceptionSerializer.java index b69b1625f..b59a9e576 100644 --- a/youlai-auth/src/main/java/com/youlai/auth/component/OAuth2ExceptionSerializer.java +++ b/youlai-auth/src/main/java/com/youlai/auth/component/OAuth2ExceptionSerializer.java @@ -5,7 +5,6 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import com.youlai.auth.exception.CustomOAuth2Exception; -import com.youlai.common.core.result.ResultCodeEnum; import lombok.SneakyThrows; diff --git a/youlai-auth/src/main/java/com/youlai/auth/component/OAuth2WebResponseExceptionTranslator.java b/youlai-auth/src/main/java/com/youlai/auth/component/OAuth2WebResponseExceptionTranslator.java index aa47e3521..4f178fa4e 100644 --- a/youlai-auth/src/main/java/com/youlai/auth/component/OAuth2WebResponseExceptionTranslator.java +++ b/youlai-auth/src/main/java/com/youlai/auth/component/OAuth2WebResponseExceptionTranslator.java @@ -1,7 +1,7 @@ package com.youlai.auth.component; import com.youlai.auth.exception.CustomOAuth2Exception; -import com.youlai.common.core.result.ResultCodeEnum; +import com.youlai.common.core.result.ResultCode; import lombok.SneakyThrows; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -63,12 +63,12 @@ public class OAuth2WebResponseExceptionTranslator implements WebResponseExceptio private static class InvalidException extends OAuth2Exception { public InvalidException() { - super(ResultCodeEnum.USER_PASSWORD_ERROR.getMsg()); + super(ResultCode.USERNAME_OR_PASSWORD_ERROR.getMsg()); } @Override public String getOAuth2ErrorCode() { - return ResultCodeEnum.USER_PASSWORD_ERROR.getCode(); + return ResultCode.USERNAME_OR_PASSWORD_ERROR.getCode(); } @Override diff --git a/youlai-auth/src/main/java/com/youlai/auth/controller/AuthController.java b/youlai-auth/src/main/java/com/youlai/auth/controller/AuthController.java index 157afda82..fcd967440 100644 --- a/youlai-auth/src/main/java/com/youlai/auth/controller/AuthController.java +++ b/youlai-auth/src/main/java/com/youlai/auth/controller/AuthController.java @@ -1,40 +1,38 @@ package com.youlai.auth.controller; +import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.nimbusds.jose.JWSObject; import com.youlai.admin.api.dto.UserDTO; import com.youlai.auth.domain.Oauth2Token; import com.youlai.common.core.constant.AuthConstants; import com.youlai.common.core.result.Result; +import com.youlai.common.core.result.ResultCode; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; +import lombok.AllArgsConstructor; import org.apache.logging.log4j.util.Strings; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.annotation.*; import springfox.documentation.annotations.ApiIgnore; -import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.security.Principal; -import java.text.ParseException; import java.util.Map; +import java.util.concurrent.TimeUnit; -@Api(tags = "认证中心认证登录") +@Api(tags = "认证中心") @RestController @RequestMapping("/oauth") +@AllArgsConstructor public class AuthController { - @Resource private TokenEndpoint tokenEndpoint; - - @Autowired private RedisTemplate redisTemplate; @ApiOperation("Oauth2获取token") @@ -61,14 +59,19 @@ public class AuthController { } @DeleteMapping("/logout") - public Result logout(HttpServletRequest request) throws ParseException { - String token = request.getHeader(AuthConstants.JWT_TOKEN_HEADER); - JWSObject jwsObject = JWSObject.parse(token); - String payload = jwsObject.getPayload().toString(); // jwt 载体部分 - UserDTO userDTO = JSONUtil.toBean(payload, UserDTO.class); - redisTemplate.opsForValue().set("", ""); - return null; + public Result logout(HttpServletRequest request) { + String payload = request.getHeader(AuthConstants.JWT_PAYLOAD_KEY); + JSONObject jsonObject = JSONUtil.parseObj(payload); + + String jti = jsonObject.getStr("jti"); // JWT唯一标识 + long exp = jsonObject.getLong("exp"); // JWT过期时间戳 + + long currentTimeSeconds = System.currentTimeMillis() / 1000; + + if (exp < currentTimeSeconds) { // token已过期 + return Result.custom(ResultCode.INVALID_TOKEN_OR_EXPIRED); + } + redisTemplate.opsForValue().set(AuthConstants.TOKEN_BLACKLIST_PREFIX + jti, null, (exp - currentTimeSeconds), TimeUnit.SECONDS); + return Result.success(); } - - } diff --git a/youlai-gateway/src/main/java/com/youlai/gateway/component/AuthorizationManager.java b/youlai-gateway/src/main/java/com/youlai/gateway/component/AuthorizationManager.java index 55226ab5b..b206be2bb 100644 --- a/youlai-gateway/src/main/java/com/youlai/gateway/component/AuthorizationManager.java +++ b/youlai-gateway/src/main/java/com/youlai/gateway/component/AuthorizationManager.java @@ -20,7 +20,6 @@ import org.springframework.util.AntPathMatcher; import org.springframework.util.PathMatcher; import reactor.core.publisher.Mono; -import java.net.URI; import java.util.*; /** diff --git a/youlai-gateway/src/main/java/com/youlai/gateway/component/CustomServerAccessDeniedHandler.java b/youlai-gateway/src/main/java/com/youlai/gateway/component/CustomServerAccessDeniedHandler.java index 14ad1cb92..6653852bb 100644 --- a/youlai-gateway/src/main/java/com/youlai/gateway/component/CustomServerAccessDeniedHandler.java +++ b/youlai-gateway/src/main/java/com/youlai/gateway/component/CustomServerAccessDeniedHandler.java @@ -2,7 +2,7 @@ package com.youlai.gateway.component; import cn.hutool.json.JSONUtil; import com.youlai.common.core.result.Result; -import com.youlai.common.core.result.ResultCodeEnum; +import com.youlai.common.core.result.ResultCode; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -29,7 +29,7 @@ public class CustomServerAccessDeniedHandler implements ServerAccessDeniedHandle 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.custom(ResultCodeEnum.USER_ACCESS_UNAUTHORIZED)); + String body= JSONUtil.toJsonStr(Result.custom(ResultCode.USER_ACCESS_UNAUTHORIZED)); DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8"))); return response.writeWith(Mono.just(buffer)); } diff --git a/youlai-gateway/src/main/java/com/youlai/gateway/component/CustomServerAuthenticationEntryPoint.java b/youlai-gateway/src/main/java/com/youlai/gateway/component/CustomServerAuthenticationEntryPoint.java index 00f080f17..141cee1e5 100644 --- a/youlai-gateway/src/main/java/com/youlai/gateway/component/CustomServerAuthenticationEntryPoint.java +++ b/youlai-gateway/src/main/java/com/youlai/gateway/component/CustomServerAuthenticationEntryPoint.java @@ -2,7 +2,7 @@ package com.youlai.gateway.component; import cn.hutool.json.JSONUtil; import com.youlai.common.core.result.Result; -import com.youlai.common.core.result.ResultCodeEnum; +import com.youlai.common.core.result.ResultCode; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -29,7 +29,7 @@ public class CustomServerAuthenticationEntryPoint implements ServerAuthenticatio 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.custom(ResultCodeEnum.USER_ACCOUNT_UNAUTHENTICATED)); + String body = JSONUtil.toJsonStr(Result.custom(ResultCode.USER_ACCOUNT_UNAUTHENTICATED)); DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8"))); return response.writeWith(Mono.just(buffer)); } 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 242f19e21..3ee24977e 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,14 +6,12 @@ import com.youlai.common.core.constant.AuthConstants; import com.youlai.gateway.component.AuthorizationManager; import com.youlai.gateway.component.CustomServerAuthenticationEntryPoint; import com.youlai.gateway.component.CustomServerAccessDeniedHandler; -import com.youlai.gateway.filter.WhiteListRemoveJwtFilter; import lombok.AllArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.convert.converter.Converter; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; -import org.springframework.security.config.web.server.SecurityWebFiltersOrder; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; 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 0d1cc1891..7804c9056 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 @@ -1,26 +1,42 @@ package com.youlai.gateway.filter; import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; 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 lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.logging.log4j.util.Strings; +import org.springframework.beans.factory.annotation.Autowired; 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.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; +import java.nio.charset.Charset; + /** - * JWT转换成用户信息过滤器 + * 黑名单token过滤器 */ @Component @Slf4j public class AuthGlobalFilter implements GlobalFilter, Ordered { + @Autowired + private RedisTemplate redisTemplate; + @SneakyThrows @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @@ -31,9 +47,25 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered { 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唯一标识 + + 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.custom(ResultCode.INVALID_TOKEN_OR_EXPIRED)); + DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8"))); + return response.writeWith(Mono.just(buffer)); + } + ServerHttpRequest request = exchange.getRequest().mutate() - .header(AuthConstants.USER_TOKEN_HEADER, payload) - .header(AuthConstants.JWT_TOKEN_HEADER,token) + .header(AuthConstants.JWT_PAYLOAD_KEY, payload) .build(); exchange = exchange.mutate().request(request).build(); return chain.filter(exchange); diff --git a/youlai-gateway/src/main/java/com/youlai/gateway/filter/WhiteListRemoveJwtFilter.java b/youlai-gateway/src/main/java/com/youlai/gateway/filter/WhiteListRemoveJwtFilter.java deleted file mode 100644 index a712f62f3..000000000 --- a/youlai-gateway/src/main/java/com/youlai/gateway/filter/WhiteListRemoveJwtFilter.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.youlai.gateway.filter; - -import com.youlai.common.core.constant.AuthConstants; -import com.youlai.gateway.config.WhiteListConfig; -import lombok.AllArgsConstructor; -import org.apache.logging.log4j.util.Strings; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.stereotype.Component; -import org.springframework.util.AntPathMatcher; -import org.springframework.util.PathMatcher; -import org.springframework.web.server.ServerWebExchange; -import org.springframework.web.server.WebFilter; -import org.springframework.web.server.WebFilterChain; -import reactor.core.publisher.Mono; - -import java.net.URI; -import java.util.List; - -/** - * 白名单路径移除JWT请求头 - */ -@Component -@AllArgsConstructor -public class WhiteListRemoveJwtFilter implements WebFilter { - - private WhiteListConfig whiteListConfig; - - @Override - public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { - ServerHttpRequest request = exchange.getRequest(); - URI uri = request.getURI(); - PathMatcher pathMatcher = new AntPathMatcher(); - - //白名单路径移除JWT请求头 - List ignoreUrls = whiteListConfig.getUrls(); - for (String ignoreUrl : ignoreUrls) { - if (pathMatcher.match(ignoreUrl, uri.getPath())) { - request = exchange.getRequest().mutate() - .header(AuthConstants.JWT_TOKEN_HEADER, Strings.EMPTY).build(); - exchange = exchange.mutate().request(request).build(); - return chain.filter(exchange); - } - } - return chain.filter(exchange); - } -}