百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

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 资源认证(保护)

SpringBoot2 整合OAuth2实现统一认证

SpringBoot2 整合OAuth2自定义登录与授权页面

ThreadPoolExecutor 参数说明

Springboot之Actuator详解

SpringBoot配置HTTPS支持 单向认证

Tomcat配置参数connectionTimeout意义

SpringCloud Hystrix实现资源隔离应用

Spring Boot Security防重登录及在线总数

Springboot Security 基础应用 (1)

Spring Cloud Sentinel 熔断降级

Spring Cloud Nacos 开启权限验证

Spring Cloud Sentinel 流控限流

Spring Cloud Gateway应用详解1之谓词

SpringCloud zuul 动态网关配置

SpringCloud Nacos 整合feign

SpringCloud Nacos 服务消费者

相关推荐

为何越来越多的编程语言使用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)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码