Springboot整合第三方OAuth2登录详解及避坑
toyiye 2024-09-16 06:06 3 浏览 0 评论
环境:springboot2.3.10.RELEASE + OAuth2
请先阅读《SpringBoot2 整合OAuth2实现统一认证 》文章,本篇内容是调用之前写的一个OAuth2认证服务。
相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
应用配置
server:
servlet:
session:
timeout: 30m
---
spring:
security:
oauth2:
client:
provider:
xgpack:
authorization-uri: http://localhost:8208/oauth/authorize
token-uri: http://localhost:8208/oauth/token
user-info-uri: http://localhost:8208/users/userinfo
user-name-attribute: name
registration:
auth2:
provider: xgpack
client-id: 1
client-secret: 1
authorization-grant-type: authorization_code
redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
---
logging:
level:
org.springframework.security: debug
说明:
authorization-uri:你的认证服务地址
token-uri:获取token地址
user-info-uri:获取用户信息地址
user-name-attribute:用户名,在获取用户信息接口返回的json中的key
redirect-uri:跳转地址,这个地址必须与服务认证那里配置的跳转地址一致。{baseUrl}系统会自动替换你当前服务的地址及端口,{registrationId} 会被替换成auth2。默认情况下系统只能处理/login/oauth2/code/* 地址,当登录成功后跳转回来这个地址时由OAuth2LoginAuthenticationFilter过滤器进行处理。部分源码如下:
public class OAuth2LoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public static final String DEFAULT_FILTER_PROCESSES_URI = "/login/oauth2/code/*";
private static final String AUTHORIZATION_REQUEST_NOT_FOUND_ERROR_CODE = "authorization_request_not_found";
private static final String CLIENT_REGISTRATION_NOT_FOUND_ERROR_CODE = "client_registration_not_found";
private ClientRegistrationRepository clientRegistrationRepository;
private OAuth2AuthorizedClientRepository authorizedClientRepository;
private AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository =
new HttpSessionOAuth2AuthorizationRequestRepository();
public OAuth2LoginAuthenticationFilter(ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientService authorizedClientService) {
this(clientRegistrationRepository, authorizedClientService, DEFAULT_FILTER_PROCESSES_URI);
}
// ....
}
DEFAULT_FILTER_PROCESSES_URI:默认该过滤器能处理的请求地址。该过滤器的作用就是获取token信息然后交由AuthenticationManager以登录最终用户。
Security配置
@Configuration
public class OAuthConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() ;
http.authorizeRequests()
.antMatchers("/error", "/webjars/**", "/resources/**", "/index/**").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login()
.logout();
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.ALWAYS);
}
}
这里设置了下session,因为不设置在跟踪源码的时候你会发现session始终为空
到此配置就完成了,接下来进行测试。
访问测试接口/home
登录后出现如下错误信息
这个错误的原因就是从session中无法获取OAuth2AuthorizationRequest保存的对象。
OAuth2LoginAuthenticationFilter.java
跟踪源码查看问题出在哪里?
进入OAuth2LoginAuthenticationFilter类
进入选中的方法中
注意这里的
Map<String, OAuth2AuthorizationRequest> authorizationRequests = session == null ? null : (Map<String, OAuth2AuthorizationRequest>) session.getAttribute(this.sessionAttributeName);
这行代码是从session中获取跳转前保存在session中的OAuth2AuthorizationRequest对象,没有被获取
在整个处理流中并不能从session中获取信息OAuth2AuthorizationRequest信息。那这个对象又是在哪里设置的呢?是由另外一个核心Filter处理的OAuth2AuthorizationRequestRedirectFilter。
注意:这里有两次的重定向,首次这里的if肯定是不会进入的,因为该过滤器默认处理的请求地址是/oauth2/authorization
public class OAuth2AuthorizationRequestRedirectFilter extends OncePerRequestFilter {
public static final String DEFAULT_AUTHORIZATION_REQUEST_BASE_URI = "/oauth2/authorization";
}
第一次重定向:
接着OAuth2AuthorizationRequestRedirectFilter就能处理该请求,并且进入if语句中进行重定向到认证服务。而设置保存OAuth2AuthorizationRequest对象到session中就在如下方法中。
this.sendRedirectForAuthorization(request, response, authorizationRequest);
设置和获取使用的key都是同一个(确保没有错误)
测试session是否真的有东西?我把跳转到认证服务的地址改错,然后请求,接着用另外一个接口打印session中的内容。
session中是有内容的,接着吧跳转地址改对,再看session中的内容
跳转到登录页面后,不进行登录,接着访问打印session的接口:
session中已经没有内容了。
证实:session是跳转到了认证服务后就没有了。难道真的是stackoverflow上所说?
翻译过来就是:
这些错误意味着找不到授权请求.授权请求存储在会话中,因此有些会话未被存储.默认情况下,会话由cookie管理.
所以我认为这可能是因为你在localhost上运行了所有东西,所以第一个cookie由localhost:8080设置来存储授权请求会话数据,&当你登录到localhost:8081时,它会为它的会话设置另一个cookie。(这里经查,cookie同ip不同端口,cookie共享)。
最后来个结果图,能够返回code,有了这个就可以获取token,获取了token就可以获取用户信息,然后将用户信息交由AuthenticationManager管理实现登录。
解决上面的问题
在c:\windows\System32\drivers\etc\host文件中添加了如下
让我们的认证服务通过这个域名访问,修改应用配置文件:
spring:
security:
oauth2:
client:
provider:
xgpack:
authorization-uri: http://www.xg.com:8208/oauth/authorize
token-uri: http://www.xg.com:8208/oauth/token
user-info-uri: http://www.xg.com:8208/users/userinfo
user-name-attribute: name
registration:
auth2:
provider: xgpack
client-id: 1
client-secret: 1
authorization-grant-type: authorization_code
redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
都修改域名形式,这样我们的cookie应该不会被替换了。接下来再次测试,果然成功了。这里的处理流程是:获取token,获取token后调用获取用户信息接口。
1、自动调用获取token的接口
OAuth2LoginAuthenticationProvider.java
2、通过上一步获取的token再自动调用获取用户信息表
注意:获取用户信息的接口,你应该只验证token是否合法即可,不要用security再进行拦截了。security应该排除这个接口。接口如下:
@GetMapping("/userinfo")
public Map<String, Object> userinfo(){
Map<String, Object> res = new HashMap<>() ;
String token = extractToken() ;
OAuth2Authentication auth = tokenService.loadAuthentication(token) ;
res.put("name", auth.getName()) ;
return res ;
}
整合第三方OAuth2的核心过滤器:
OAuth2AuthorizationRequestRedirectFilter.java
OAuth2LoginAuthenticationFilter.java
完毕!!!
给个关注吧谢谢
SpringBoot2 整合 OAuth2 资源认证(保护)
相关推荐
- 为何越来越多的编程语言使用JSON(为什么编程)
-
JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...
- 何时在数据库中使用 JSON(数据库用json格式存储)
-
在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...
- MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)
-
前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...
- JSON对象花样进阶(json格式对象)
-
一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...
- 深入理解 JSON 和 Form-data(json和formdata提交区别)
-
在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...
- JSON 语法(json 语法 priority)
-
JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...
- JSON语法详解(json的语法规则)
-
JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...
- MySQL JSON数据类型操作(mysql的json)
-
概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...
- JSON的数据模式(json数据格式示例)
-
像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...
- 前端学习——JSON格式详解(后端json格式)
-
JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...
- 什么是 JSON:详解 JSON 及其优势(什么叫json)
-
现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...
- PostgreSQL JSON 类型:处理结构化数据
-
PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...
- JavaScript:JSON、三种包装类(javascript 包)
-
JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...
- Python数据分析 只要1分钟 教你玩转JSON 全程干货
-
Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...
- 比较一下JSON与XML两种数据格式?(json和xml哪个好)
-
JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- r语言矩阵 (127)
- browsererror (114)
- exportexcel (119)
- cv2.bitwise_not (137)
- dump命令 (128)
- es6concat (126)
- heapify (127)
- java.security.egd (130)
- javax.annotation (117)
- jsstringsplit (117)
- js数字 (115)
- maven编译 (132)
- mysqlleft (128)
- nodejsbuffer (149)
- org.apache.commons.httpclient (126)
- org.jsoup (141)
- org.springframework.web (128)
- robotframework-ride (115)
- setnocounton (141)
- socket.gethostbyname (122)
- sqlmid (121)
- time.strptime (133)
- vscode格式化 (125)
- win32con (129)
- window.localstorage (126)