OAuth实现自定义Exception
前言
自己在查找相关问题时发现清一色连代码都不看一下的转载,真的看吐了,以下是自己根据git源码修改部分不正确代码以及部分业务,与源码有部分出入,建议直接看源码
自定义登录失败异常信息
新增CustomOauthException
- 添加自定义异常类,指定
json
序列化方式
@JsonSerialize(using=CustomOauthExceptionSerializer.class)
public class CustomOauthException extends OAuth2Exception {
public CustomOauthException(String msg) {
super(msg);
}
}
新增CustomOauthExceptionSerializer
- 添加
CustomOauthException
的序列化实现
public class CustomOauthExceptionSerializer extends StdSerializer {
public CustomOauthExceptionSerializer() {
super(CustomOauthException.class);
}
@Override
public void serialize(CustomOauthException value, JsonGenerator gen, SerializerProvider provider) throws IOException {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
gen.writeStartObject();
gen.writeStringField("error", String.valueOf(value.getHttpErrorCode()));
gen.writeStringField("message", value.getMessage());
gen.writeStringField("path", request.getServletPath());
gen.writeStringField("timestamp", String.valueOf(System.currentTimeMillis()));
if (value.getAdditionalInformation()!=null) {
for (Map.Entry entry : value.getAdditionalInformation().entrySet()) {
String key = entry.getKey();
String add = entry.getValue();
gen.writeStringField(key, add);
}
}
gen.writeEndObject();
}
}
添加CustomWebResponseExceptionTranslator
- 添加
CustomWebResponseExceptionTranslator
,登录发生异常时指定exceptionTranslator
@Component("customWebResponseExceptionTranslator")
public class CustomWebResponseExceptionTranslator implements WebResponseExceptionTranslator {
@Override
public ResponseEntity translate(Exception e) throws Exception {
OAuth2Exception oAuth2Exception = (OAuth2Exception) e;
return ResponseEntity
.status(oAuth2Exception.getHttpErrorCode())
.body(new CustomOauthException(oAuth2Exception.getMessage()));
}
}
修改AuthorizationConfig
- 指定自定义
customWebResponseExceptionTranslator
@Autowired
private AuthenticationManager auth;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
List tokenGranters = getTokenGranters(endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory());
endpoints.tokenGranter(new CompositeTokenGranter(tokenGranters));
endpoints.tokenEnhancer((oAuth2AccessToken, oAuth2Authentication) -> oAuth2AccessToken);
endpoints.authenticationManager(auth).tokenStore(tokenStore());
endpoint
s.exceptionTranslator(new CustomWebResponseExceptionTranslator());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.authenticationEntryPoint(new AuthExceptionEntryPoint());
}
/**
* 配置客户端一些信息
*
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
InMemoryClientDetailsServiceBuilder build = clients.inMemory();
if (ArrayUtils.isNotEmpty(oAuth2Properties.getClients())) {
for (OAuth2ClientProperties config : oAuth2Properties.getClients()) {
build.withClient(config.getClientId())
.secret(config.getClientSecret())
.accessTokenValiditySeconds(config.getAccessTokenValiditySeconds())
.refreshTokenValiditySeconds(60 * 60 * 24 * 15)
//OAuth2支持的验证模式
.authorizedGrantTypes("refresh_token", "password", "authorization_code")
.scopes("all");
}
}
}
//自定义验证Service
private List getTokenGranters(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
return Lists.newArrayList(
new XXXCustomTokenGranter(tokenServices, clientDetailsService, requestFactory, customUserDetailsService),
new XXXCustomTokenGranter(tokenServices, clientDetailsService, requestFactory, customUserDetailsService),
new XXCustomTokenGranter(tokenServices, clientDetailsService, requestFactory, customUserDetailsService));
}
自定义Token异常信息
添加AuthExceptionEntryPoint
- 自定义
AuthExceptionEntryPoint
用于tokan
校验失败返回信息
public class AuthExceptionEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException)
throws ServletException {
Map map = new HashMap();
map.put("error", "401");
map.put("message", authException.getMessage());
map.put("path", request.getServletPath());
map.put("timestamp", String.valueOf(System.currentTimeMillis()));
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
try {
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(response.getOutputStream(), map);
} catch (Exception e) {
throw new ServletException();
}
}
}
添加CustomAccessDeniedHandler
- 授权失败(forbidden)时返回信息
@Component("customAccessDeniedHandler")
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Autowired
private ObjectMapper objectMapper;
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setContentType("application/json;charset=UTF-8");
Map map = new HashMap();
map.put("error", "400");
map.put("message", accessDeniedException.getMessage());
map.put("path", request.getServletPath());
map.put("timestamp",String.valueOf(System.currentTimeMillis()));
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write(objectMapper.writeValueAsString(map));
}
}
修改ResourceServerConfig
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.authenticationEntryPoint(new AuthExceptionEntryPoint())
.accessDeniedHandler(new CustomAccessDeniedHandler());
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.formLogin()
//登录成功处理器
.successHandler(appLoginInSuccessHandler)
.failureHandler(appLoginFailureHandler)
.and()
//添加自定义handler
.exceptionHandling().authenticationEntryPoint(new AuthExceptionEntryPoint())
.and()
.apply(permitAllSecurityConfig)
.and()
.authorizeRequests()
.antMatchers("/user").hasRole("USER")
.antMatchers("/forbidden").hasRole("ADMIN")
.antMatchers("/permitAll").permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable();
}