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)自定义异常转换类

 @Slf4j
public class Auth2ResponseExceptionTranslator implements WebResponseExceptionTranslator { @Override
public ResponseEntity<OAuth2Exception> 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。

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

即1、自定义响应处理逻辑SecurityAuthenticationEntryPoint 2、自定义处理逻辑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) 问题整理的更多相关文章

  1. Spring Security OAuth2 授权码模式

     背景: 由于业务实现中涉及到接入第三方系统(app接入有赞商城等),所以涉及到第三方系统需要获取用户信息(用户手机号.姓名等),为了保证用户信息的安全和接入方式的统一, 采用Oauth2四种模式之一 ...

  2. Spring Security OAuth2 微服务认证中心自定义授权模式扩展以及常见登录认证场景下的应用实战

    一. 前言 [APP 移动端]Spring Security OAuth2 手机短信验证码模式 [微信小程序]Spring Security OAuth2 微信授权模式 [管理系统]Spring Se ...

  3. Spring Security OAuth2 Demo —— 隐式授权模式(Implicit)

    本文可以转载,但请注明出处https://www.cnblogs.com/hellxz/p/oauth2_impilit_pattern.html 写在前面 在文章OAuth 2.0 概念及授权流程梳 ...

  4. Spring Security OAuth2.0认证授权四:分布式系统认证授权

    Spring Security OAuth2.0认证授权系列文章 Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授 ...

  5. 【Spring Cloud & Alibaba 实战 | 总结篇】Spring Cloud Gateway + Spring Security OAuth2 + JWT 实现微服务统一认证授权和鉴权

    一. 前言 hi,大家好~ 好久没更文了,期间主要致力于项目的功能升级和问题修复中,经过一年时间的打磨,[有来]终于迎来v2.0版本,相较于v1.x版本主要完善了OAuth2认证授权.鉴权的逻辑,结合 ...

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

    项目security_simple(认证授权项目) 1.新建springboot项目 这儿选择springboot版本我选择的是2.0.6 点击finish后完成项目的创建 2.引入maven依赖  ...

  7. 转 - spring security oauth2 password授权模式

    原贴地址: https://segmentfault.com/a/1190000012260914#articleHeader6 序 前面的一篇文章讲了spring security oauth2的c ...

  8. Spring Cloud实战 | 最终篇:Spring Cloud Gateway+Spring Security OAuth2集成统一认证授权平台下实现注销使JWT失效方案

    一. 前言 在上一篇文章介绍 youlai-mall 项目中,通过整合Spring Cloud Gateway.Spring Security OAuth2.JWT等技术实现了微服务下统一认证授权平台 ...

  9. Spring Security OAuth2.0认证授权二:搭建资源服务

    在上一篇文章[Spring Security OAuth2.0认证授权一:框架搭建和认证测试](https://www.cnblogs.com/kuangdaoyizhimei/p/14250374. ...

随机推荐

  1. Android 混淆代码总结

    为了防止自己的劳动成果被别人窃取,混淆代码能有效防止被反编译,下面来总结以下混淆代码的步骤: 1. 大家也许都注意到新建一个工程会看到项目下边有这样proguard-project.txt一个文件,这 ...

  2. 几种TCP连接中出现RST的情况(转载)

    TCP RST 网络 linux 目录[-] 1 端口未打开 2 请求超时 3 提前关闭 4 在一个已关闭的socket上收到数据 总结 参考文献: 应该没有人会质疑,现在是一个网络时代了.应该不少程 ...

  3. 在Win7中IIS配置Asp.Net虚拟文件夹的方法及错误总结!

    在Win7中IIS配置Asp.Net虚拟文件夹的方法总结! 一.右键[站点].点击[加入虚拟文件夹]或[虚拟应用程序],笔者建议最好建立虚拟应用程序,由于这就跟一个站点差点儿相同.不用考虑路径问题. ...

  4. C#Virtual和Override的几种组合

    情况1: class A{public void Show()} class B:A{public void Show()} 编译通过,有警告让在B的方法里添加new关键字,以便将A的方法隐藏 编译时 ...

  5. js 时间戳

    https://www.cnblogs.com/crf-Aaron/archive/2017/11/16/7844462.html var time = '2018-03-22 00:00:00'.r ...

  6. QT .pro文件 LIBS用法详解

    在程序中需要使用到团队其它成员开发的静态库和动态库,起初是知道使用LIBS变量在在.pro文件中指定需要包含的库,但是实际使用的时候却遇到很大麻烦,但其实确实是因为自己看官方文档不太用心造成的. 下面 ...

  7. 进程隐藏与进程保护(SSDT Hook 实现)(三)

    文章目录: 1. 引子: 2. 获取当前系统下所有进程: 3. 服务管理(安装,启动,停止,卸载): 4. 应用程序和内核程序通信: 5. 小结: 1. 引子: 关于这个 SSDT Hook 实现进程 ...

  8. 文件io之——read/write

    read函数从打开的设备或文件中读取数据. #include <unistd.h>ssize_t read(int fd, void *buf, size_t count);返回值:成功返 ...

  9. CSRF学习笔记之CSRF的攻击与防御以及审计【00x3】

    Hight.php完整代码如下: <?php if (isset($_GET['Change'])) { // Turn requests into variables $pass_curr = ...

  10. List、Set、Map集合大杂烩

    java集合主要分三种:list.set.map:当中list和set都继承自Collection接口,两者最大差别是set不能包括反复元素 list的经常使用实现类有: ArrayList:大小可变 ...