From 339351625164d32e0eb76552cc04fbf8a3a1aa30 Mon Sep 17 00:00:00 2001 From: haoxr <1490493387@qq.com> Date: Mon, 21 Sep 2020 18:02:47 +0800 Subject: [PATCH] =?UTF-8?q?feat:oauth2=E8=AE=A4=E8=AF=81=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 3 - .../component/ResourceRoleRulesHolder.java | 14 +--- .../component/OAuth2ExceptionSerializer.java | 33 ++++++++ .../OAuth2WebResponseExceptionTranslator.java | 79 +++++++++++++++++++ .../config/AuthorizationServerConfig.java | 10 ++- .../auth/exception/CustomOAuth2Exception.java | 24 ++++++ .../auth/service/UserDetailsServiceImpl.java | 2 +- 7 files changed, 145 insertions(+), 20 deletions(-) create mode 100644 youlai-auth/src/main/java/com/youlai/auth/component/OAuth2ExceptionSerializer.java create mode 100644 youlai-auth/src/main/java/com/youlai/auth/component/OAuth2WebResponseExceptionTranslator.java create mode 100644 youlai-auth/src/main/java/com/youlai/auth/exception/CustomOAuth2Exception.java diff --git a/pom.xml b/pom.xml index 64f55dd1f..bcca74fd8 100644 --- a/pom.xml +++ b/pom.xml @@ -10,12 +10,9 @@ pom - youlai-admin youlai-common - youlai-auth youlai-admin-api youlai-admin - youlai-admin-api youlai-auth diff --git a/youlai-admin/src/main/java/com/youlai/admin/component/ResourceRoleRulesHolder.java b/youlai-admin/src/main/java/com/youlai/admin/component/ResourceRoleRulesHolder.java index cf3485f44..f4ef3fdb5 100644 --- a/youlai-admin/src/main/java/com/youlai/admin/component/ResourceRoleRulesHolder.java +++ b/youlai-admin/src/main/java/com/youlai/admin/component/ResourceRoleRulesHolder.java @@ -15,16 +15,4 @@ import java.util.TreeMap; @Component @AllArgsConstructor public class ResourceRoleRulesHolder { - - private RedisTemplate redisTemplate; - - @PostConstruct - public void initResourceRolesMap() { - Map> resourceRoleMap = new TreeMap<>(); - List roleNames = new ArrayList<>(); - roleNames.add(AuthConstants.AUTHORITY_PREFIX + "1"); - resourceRoleMap.put("/youlai-admin/**", roleNames); - redisTemplate.delete(AuthConstants.RESOURCE_ROLES_MAP_KEY); - redisTemplate.opsForHash().putAll(AuthConstants.RESOURCE_ROLES_MAP_KEY, resourceRoleMap); - } -} + } 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 new file mode 100644 index 000000000..b69b1625f --- /dev/null +++ b/youlai-auth/src/main/java/com/youlai/auth/component/OAuth2ExceptionSerializer.java @@ -0,0 +1,33 @@ +package com.youlai.auth.component; + + +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; + + +/** + * 异常信息格式化 + * + * @author haoxr + * @date 2020/09/21 + */ +public class OAuth2ExceptionSerializer extends StdSerializer { + + public OAuth2ExceptionSerializer() { + super(CustomOAuth2Exception.class); + } + + @Override + @SneakyThrows + public void serialize(CustomOAuth2Exception e, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) { + jsonGenerator.writeStartObject(); + jsonGenerator.writeObjectField("code",e.getOAuth2ErrorCode()); + jsonGenerator.writeStringField("msg", e.getMessage()); + jsonGenerator.writeStringField("data", e.getOAuth2ErrorCode()); + jsonGenerator.writeEndObject(); + } +} 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 new file mode 100644 index 000000000..aa47e3521 --- /dev/null +++ b/youlai-auth/src/main/java/com/youlai/auth/component/OAuth2WebResponseExceptionTranslator.java @@ -0,0 +1,79 @@ +package com.youlai.auth.component; + +import com.youlai.auth.exception.CustomOAuth2Exception; +import com.youlai.common.core.result.ResultCodeEnum; +import lombok.SneakyThrows; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.oauth2.common.DefaultThrowableAnalyzer; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.common.exceptions.ClientAuthenticationException; +import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException; +import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; +import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; +import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator; +import org.springframework.security.web.util.ThrowableAnalyzer; +import org.springframework.stereotype.Component; + +/** + * 认证接口异常转换器 + * + * @author haoxr + * @date 2020/09/21 + */ +@Component +public class OAuth2WebResponseExceptionTranslator implements WebResponseExceptionTranslator { + + private ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer(); + + @Override + @SneakyThrows + public ResponseEntity translate(Exception e) { + Throwable[] causeChain = throwableAnalyzer.determineCauseChain(e); + + Exception exception = (InvalidGrantException) throwableAnalyzer.getFirstThrowableOfType(InvalidGrantException.class, + causeChain); + if (exception != null) { + return handleOAuth2Exception(new InvalidException()); + } + return null; + } + + + private ResponseEntity handleOAuth2Exception(OAuth2Exception e) { + int status = e.getHttpErrorCode(); + HttpHeaders headers = new HttpHeaders(); + headers.set(HttpHeaders.CACHE_CONTROL, "no-store"); + headers.set(HttpHeaders.PRAGMA, "no-cache"); + if (status == HttpStatus.UNAUTHORIZED.value() || (e instanceof InsufficientScopeException)) { + headers.set(HttpHeaders.WWW_AUTHENTICATE, + String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, e.getSummary())); + } + + // 客户端异常直接返回客户端,不然无法解析 + if (e instanceof ClientAuthenticationException) { + return new ResponseEntity<>(e, headers, HttpStatus.valueOf(status)); + } + return new ResponseEntity<>(new CustomOAuth2Exception(e.getMessage(), e.getOAuth2ErrorCode()), headers, + HttpStatus.valueOf(status)); + } + + + private static class InvalidException extends OAuth2Exception { + + public InvalidException() { + super(ResultCodeEnum.USER_PASSWORD_ERROR.getMsg()); + } + + @Override + public String getOAuth2ErrorCode() { + return ResultCodeEnum.USER_PASSWORD_ERROR.getCode(); + } + + @Override + public int getHttpErrorCode() { + return HttpStatus.BAD_REQUEST.value(); + } + } +} diff --git a/youlai-auth/src/main/java/com/youlai/auth/config/AuthorizationServerConfig.java b/youlai-auth/src/main/java/com/youlai/auth/config/AuthorizationServerConfig.java index d497ac097..96202f042 100644 --- a/youlai-auth/src/main/java/com/youlai/auth/config/AuthorizationServerConfig.java +++ b/youlai-auth/src/main/java/com/youlai/auth/config/AuthorizationServerConfig.java @@ -1,5 +1,6 @@ package com.youlai.auth.config; +import com.youlai.auth.component.OAuth2WebResponseExceptionTranslator; import com.youlai.auth.domain.User; import com.youlai.auth.service.JdbcClientDetailsServiceImpl; import com.youlai.auth.service.UserDetailsServiceImpl; @@ -39,6 +40,7 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap private DataSource dataSource; private AuthenticationManager authenticationManager; private UserDetailsServiceImpl userDetailsService; + private OAuth2WebResponseExceptionTranslator oAuth2WebResponseExceptionTranslator; /** * 配置客户端详情 @@ -68,9 +70,11 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap .tokenEnhancer(tokenEnhancerChain) .userDetailsService(userDetailsService) // refresh token有两种使用方式:重复使用(true)、非重复使用(false),默认为true - // 1,重复使用:access token过期刷新时, refresh token过期时间未改变,仍以初次生成的时间为准 - // 2,非重复使用:access token过期刷新时, refresh token过期时间延续,在refresh token有效期内刷新便永不失效达到无需再次登录的目的 - .reuseRefreshTokens(false); + // 1 重复使用:access token过期刷新时, refresh token过期时间未改变,仍以初次生成的时间为准 + // 2 非重复使用:access token过期刷新时, refresh token过期时间延续,在refresh token有效期内刷新便永不失效达到无需再次登录的目的 + .reuseRefreshTokens(false) + // .exceptionTranslator(oAuth2WebResponseExceptionTranslator) + ; } /** diff --git a/youlai-auth/src/main/java/com/youlai/auth/exception/CustomOAuth2Exception.java b/youlai-auth/src/main/java/com/youlai/auth/exception/CustomOAuth2Exception.java new file mode 100644 index 000000000..495b79980 --- /dev/null +++ b/youlai-auth/src/main/java/com/youlai/auth/exception/CustomOAuth2Exception.java @@ -0,0 +1,24 @@ +package com.youlai.auth.exception; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.youlai.auth.component.OAuth2ExceptionSerializer; +import lombok.Getter; +import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; + +/** + * 自定义认证异常 + * + * @author haoxr + * @date 2020/09/21 + */ +@JsonSerialize(using = OAuth2ExceptionSerializer.class) +public class CustomOAuth2Exception extends OAuth2Exception { + + @Getter + private String oAuth2ErrorCode; + + public CustomOAuth2Exception(String msg, String oAuth2ErrorCode) { + super(msg); + this.oAuth2ErrorCode = oAuth2ErrorCode; + } +} diff --git a/youlai-auth/src/main/java/com/youlai/auth/service/UserDetailsServiceImpl.java b/youlai-auth/src/main/java/com/youlai/auth/service/UserDetailsServiceImpl.java index ddf094239..d084805e6 100644 --- a/youlai-auth/src/main/java/com/youlai/auth/service/UserDetailsServiceImpl.java +++ b/youlai-auth/src/main/java/com/youlai/auth/service/UserDetailsServiceImpl.java @@ -33,7 +33,7 @@ public class UserDetailsServiceImpl implements UserDetailsService { String clientId = request.getParameter("client_id"); UserDTO userDTO = adminUserService.loadUserByUsername(username); if (userDTO == null) { - throw new UsernameNotFoundException("用户名或者密码错误"); + throw new UsernameNotFoundException("用户不存在"); } userDTO.setClientId(clientId); User user = new User(userDTO);