【OAuth2】Spring Security OAuth2 授权失败(401) 问题整理 |
您所在的位置:网站首页 › 乐高45024教案 › 【OAuth2】Spring Security OAuth2 授权失败(401) 问题整理 |
文章目录
一、免登录接口校验token问题二、Token失效返回的是状态401的错误
Spring Cloud架构中采用Spring Security OAuth2作为权限控制,关于OAuth2详细介绍可以参考阮一峰的网络日志理解OAuth 2.0 项目中采用OAuth2四种模式中的两种,Password模式和Client模式, Password模式用于控制用户的登录,Client模式用于控制后端服务相互调用。 权限架构调整后在近期发现一些问题,由于网上资料不多,只能单步调试方式看源码 (其实带着问题看源码是最好的方式)。现在将问题和解决方案整理如下: 一、免登录接口校验token问题问题:APP端反馈,一些免登录接口会校验token 详细:经过测试发现,免登录接口 如果传了access_token会对token合法性就行校验,如果不传接口不会校验,这导致了免登录接口的过期token会报错 排查:经过查看源码发现spring-security-oauth2的过滤器 ==OAuth2AuthenticationProcessingFilter==会对请求进行拦截,(具体源码就不截图了) 如果存在access_token则会根据userInfoEndpointUrl去认证服务器上校验token信息,如果不存在access_token则会继续执行spring-security的拦截器FilterSecurityInterceptor。 FilterSecurityInterceptor对路径是否需要授权,已经授权是否通过做校验~解决: 可以采用过滤器在执行到核心过滤器OAuth2AuthenticationProcessingFilter ,将不需要授权的请求头中的access_token过滤掉。或者APP免登录接口不传token 最终采用的是后者 二、Token失效返回的是状态401的错误1、问题: APP端反馈,传递失效access_token,返回401状态,期望是200同时以错误码方式提示token失效。 排查:经过单步调试分析源码发现,token失效后,认证服务器会抛出异常,同时响应给资源服务器,资源服务发现认证服务器的错误后会抛出InvalideException。 抛出的异常会经过默认的DefaultWebResponseExceptionTranslator处理然后 Reseponse给Client端。 解决:通过上面的分析指导。最后的异常是在DefaultWebResponseExceptionTranslator 处理的,所以只需要 自定义实现类Implements WebResponseExceptionTranslator接口处理异常装换逻辑,使得自定义的类生效(1)自定义异常转换类 @Slf4j public class Auth2ResponseExceptionTranslator implements WebResponseExceptionTranslator { @Override public ResponseEntity translate(Exception e) { log.error("Auth2异常", e); Throwable throwable = e.getCause(); if (throwable instanceof InvalidTokenException) { log.info("token失效:{}", throwable); return new ResponseEntity(new Message(ServerConstant.INVALID_TOKEN.getMsg(), ServerConstant.INVALID_TOKEN.getCode()), HttpStatus.OK); } return new ResponseEntity(new Message(e.getMessage(), String.valueOf(HttpStatus.METHOD_NOT_ALLOWED.value())), HttpStatus.METHOD_NOT_ALLOWED); } }(2)资源服务器中使得自定义类生效 @Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { // 定义异常转换类生效 AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint(); ((OAuth2AuthenticationEntryPoint) authenticationEntryPoint).setExceptionTranslator(new Auth2ResponseExceptionTranslator()); resources.authenticationEntryPoint(authenticationEntryPoint); } @Override public void configure(HttpSecurity http) throws Exception { http .csrf().disable() .exceptionHandling() // 定义的不存在access_token时候响应 .authenticationEntryPoint(new SecurityAuthenticationEntryPoint()) .and() .authorizeRequests().antMatchers("/**/**").permitAll() .anyRequest().authenticated() .and() .httpBasic().disable(); } }2、问题:测试发现授权接口,当请求参数中不存在access_token时发现接口返回错误信息: {"timestamp":1539337154336,"status":401,"error":"Unauthorized","message":"No message available","path":"/app/businessCode/list"}排查:经过前面的分析发现,上面提到Security的FilterSecurityInterceptor对OAuth2中返回的信息和本身配置校验后,抛出AccessDenyException。 解决:经过上面的几个问题的处理,发现思路还是一样的,需要定义响应结果,即 **自定义响应处理逻辑SecurityAuthenticationEntryPoint **自定义处理逻辑SecurityAuthenticationEntryPoint生效(见上面的配置)SecurityAuthenticationEntryPoint具体实现: @Slf4j public class SecurityAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { log.error("Spring Securtiy异常", authException); response.setCharacterEncoding("UTF-8"); response.setContentType("application/json; charset=utf-8"); PrintWriter out = response.getWriter(); out.print(JSON.toJSONString(new Message(ServerConstant.INVALID_TOKEN.getMsg(), ServerConstant.INVALID_TOKEN.getCode()))); } }本文转载自博客园作者**浮生半日**的Spring Security OAuth2 授权失败(401) 问题整理一文。 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |