Spring Security OAuth2 授权失败(401 问题整理

Spring Cloud架构中采用Spring Security OAuth2作为权限控制,关于OAuth2详细介绍可以参考 http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html

项目中采用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)自定义异常转换类

 1 @Slf4j
 2 public class Auth2ResponseExceptionTranslator implements WebResponseExceptionTranslator {
 3
 4     @Override
 5     public ResponseEntity<OAuth2Exception> translate(Exception e) {
 6         log.error("Auth2异常", e);
 7         Throwable throwable = e.getCause();
 8         if (throwable instanceof InvalidTokenException) {
 9             log.info("token失效:{}", throwable);
10             return new ResponseEntity(new Message<>(ServerConstant.INVALID_TOKEN.getMsg(), ServerConstant.INVALID_TOKEN.getCode()), HttpStatus.OK);
11         }
12         return new ResponseEntity(new Message(e.getMessage(), String.valueOf(HttpStatus.METHOD_NOT_ALLOWED.value())), HttpStatus.METHOD_NOT_ALLOWED);
13     }
14 }

   (2)资源服务器中使得自定义类生效

 1 @Configuration
 2 @EnableResourceServer
 3 public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
 4
 5
 6   @Override
 7   public void configure(ResourceServerSecurityConfigurer resources) throws Exception {       // 定义异常转换类生效
 8     AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
 9     ((OAuth2AuthenticationEntryPoint) authenticationEntryPoint).setExceptionTranslator(new Auth2ResponseExceptionTranslator());
10     resources.authenticationEntryPoint(authenticationEntryPoint);
11   }
12
13
14   @Override
15   public void configure(HttpSecurity http) throws Exception {
16     http
17         .csrf().disable()
18         .exceptionHandling()            // 定义的不存在access_token时候响应
19         .authenticationEntryPoint(new SecurityAuthenticationEntryPoint())
20         .and()
21         .authorizeRequests().antMatchers("/**/**").permitAll()
22         .anyRequest().authenticated()
23         .and()
24         .httpBasic().disable();
25   }

2、问题:测试发现授权接口,当请求参数中不存在access_token时发现接口返回错误信息:
                {"timestamp":1539337154336,"status":401,"error":"Unauthorized","message":"No message available","path":"/app/businessCode/list"}

排查:经过前面的分析发现,上面提到Security的FilterSecurityInterceptor对OAuth2中返回的信息和本身配置校验后,抛出AccessDenyException。

解决:经过上面的几个问题的处理,发现思路还是一样的,需要定义响应结果,

即1、自定义响应处理逻辑SecurityAuthenticationEntryPoint 2、自定义处理逻辑SecurityAuthenticationEntryPoint生效(见上面的配置)

SecurityAuthenticationEntryPoint具体实现

 1 @Slf4j
 2 public class SecurityAuthenticationEntryPoint implements AuthenticationEntryPoint {
 3
 4     @Override
 5     public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
 6        log.error("Spring Securtiy异常", authException);
 7        response.setCharacterEncoding("UTF-8");
 8        response.setContentType("application/json; charset=utf-8");
 9        PrintWriter out = response.getWriter();
10        out.print(JSON.toJSONString(new Message<>(ServerConstant.INVALID_TOKEN.getMsg(), ServerConstant.INVALID_TOKEN.getCode())));
11     }
12 }

  

原文地址:https://www.cnblogs.com/mxmbk/p/9782409.html

时间: 2024-10-07 03:03:55

Spring Security OAuth2 授权失败(401 问题整理的相关文章

Spring Security OAuth2 授权码模式

 背景: 由于业务实现中涉及到接入第三方系统(app接入有赞商城等),所以涉及到第三方系统需要获取用户信息(用户手机号.姓名等),为了保证用户信息的安全和接入方式的统一, 采用Oauth2四种模式之一的授权码模式.  介绍:        第三方系统调用我方提供的授权接口(步骤1) 用户同意授权,后跳转第三方系统(步骤2.3) 第三方系统获得code,根据code到我方系统获取token(步骤5.6 ) 根据获取token访问受保护的资源(步骤8.9)    实际应用中由于合作商户,所以需要直接

springboot+spring security +oauth2.0 demo搭建(password模式)(认证授权端与资源服务端分离的形式)

项目security_simple(认证授权项目) 1.新建springboot项目 这儿选择springboot版本我选择的是2.0.6 点击finish后完成项目的创建 2.引入maven依赖  下面是我引入的依赖 1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=&q

Spring Security 解析(七) —— Spring Security Oauth2 源码解析

Spring Security 解析(七) -- Spring Security Oauth2 源码解析 ??在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因此决定先把Spring Security .Spring Security Oauth2 等权限.认证相关的内容.原理及设计学习并整理一遍.本系列文章就是在学习的过程中加强印象和理解所撰写的,如有侵权请告知. 项目环境: JDK1.8 Spring boot 2.x Spring Security

Spring security oauth2最简单入门环境搭建

关于OAuth2的一些简介,见我的上篇blog:http://wwwcomy.iteye.com/blog/2229889 PS:貌似内容太水直接被鹳狸猿干沉.. 友情提示 学习曲线:spring+spring mvc+spring security+Oauth2基本姿势,如果前面都没看过请及时关闭本网页. 我有信心我的这个blog应该是迄今为止使用spring security oauth2最简单的hello world app介绍了,如果你下下来附件源码还看不懂,请留言.. 其他能搜到的如h

【OAuth2.0】Spring Security OAuth2.0篇之初识

不吐不快 因为项目需求开始接触OAuth2.0授权协议.断断续续接触了有两周左右的时间.不得不吐槽的,依然是自己的学习习惯问题,总是着急想了解一切,习惯性地钻牛角尖去理解小的细节,而不是从宏观上去掌握,或者说先用起来(少年,一辈子辣么长,你这么着急合适吗?).好在前人们已经做好了很好的demo,我自己照着抄一抄也就理解了大概如何用,依旧手残党,依旧敲不出好代码.忏悔- WHAT? 项目之中实际使用OAuth2.0实现是用的Spring Security OAuth2.0,一套基于Spring S

Spring Security Oauth2 : Possible CSRF detected

Spring Security Oauth2 : Possible CSRF detected 使用Spring Security 作为 Oauth2 授权服务器时,在授权服务器登录授权后,重定向到客户端服务器时,出现了401 Unauthorized 错误.明明已经授权了,为何还会未授权了. 跟踪代码发现,抛出了这个异常: "Possible CSRF detected - state parameter was required but no state could be found&quo

Spring Security OAuth2 Demo —— 密码模式(Password)

前情回顾 前几节分享了OAuth2的流程与授权码模式和隐式授权模式两种的Demo,我们了解到授权码模式是OAuth2四种模式流程最复杂模式,复杂程度由大至小:授权码模式 > 隐式授权模式 > 密码模式 > 客户端模式 其中密码模式的流程是:让用户填写表单提交到授权服务器,表单中包含用户的用户名.密码.客户端的id和密钥的加密串,授权服务器先解析并校验客户端信息,然后校验用户信息,完全通过返回access_token,否则默认都是401 http状态码,提示未授权无法访问 本文目标 编写与

spring security oauth2 jwt 认证和资源分离的配置文件(java类配置版)

最近再学习spring security oauth2.下载了官方的例子sparklr2和tonr2进行学习.但是例子里包含的东西太多,不知道最简单最主要的配置有哪些.所以决定自己尝试搭建简单版本的例子.学习的过程中搭建了认证和资源在一个工程的例子,将token存储在数据库的例子等等 .最后做了这个认证和资源分离的jwt tokens版本.网上找了一些可用的代码然后做了一个整理, 同时测试了哪些代码是必须的.可能仍有一些不必要的代码在,欢迎大家赐教. 一.创建三个spring boot 工程,分

Spring Security 入门(1-3)Spring Security oauth2.0 指南

入门 这是支持OAuth2.0的用户指南.对于OAuth1.0,一切都是不同的,所以看它的用户指南. 本用户指南分为两个部分,第一部分是OAuth2.0提供端(OAuth 2.0 Provider),第二部分是OAuth2.0的客户端(OAuth 2.0 Client) OAuth2.0提供端 OAuth2.0的提供端的用途是负责将受保护的资源暴露出去.建立一个可以访问受保护的资源的客户端列表. 提供端是通过管理和验证可用于访问受保护的资源的OAuth 2令牌来做的. 在适当的地方,提供端必须为