Springboot整合第三方OAuth2登录详解及避坑

导读:本篇文章讲解 Springboot整合第三方OAuth2登录详解及避坑,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

环境: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始终为空

Springboot整合第三方OAuth2登录详解及避坑

 

到此配置就完成了,接下来进行测试。

访问测试接口/home

Springboot整合第三方OAuth2登录详解及避坑

 

登录后出现如下错误信息

Springboot整合第三方OAuth2登录详解及避坑

 

这个错误的原因就是从session中无法获取
OAuth2AuthorizationRequest保存的对象。

OAuth2LoginAuthenticationFilter.java

Springboot整合第三方OAuth2登录详解及避坑

 

跟踪源码查看问题出在哪里?

进入
OAuth2LoginAuthenticationFilter类

Springboot整合第三方OAuth2登录详解及避坑

 

进入选中的方法中

Springboot整合第三方OAuth2登录详解及避坑

 

注意这里的


Map<String, OAuth2AuthorizationRequest> authorizationRequests = session == null ? null : (Map<String, OAuth2AuthorizationRequest>) session.getAttribute(this.sessionAttributeName);

这行代码是从session中获取跳转前保存在session中的
OAuth2AuthorizationRequest对象,没有被获取

Springboot整合第三方OAuth2登录详解及避坑

 

Springboot整合第三方OAuth2登录详解及避坑

 

在整个处理流中并不能从session中获取信息
OAuth2AuthorizationRequest信息。那这个对象又是在哪里设置的呢?是由另外一个核心Filter处理的
OAuth2AuthorizationRequestRedirectFilter。

Springboot整合第三方OAuth2登录详解及避坑

 

注意:这里有两次的重定向,首次这里的if肯定是不会进入的,因为该过滤器默认处理的请求地址是/oauth2/authorization

public class OAuth2AuthorizationRequestRedirectFilter extends OncePerRequestFilter {
  public static final String DEFAULT_AUTHORIZATION_REQUEST_BASE_URI = "/oauth2/authorization";
}

第一次重定向:

Springboot整合第三方OAuth2登录详解及避坑

 

接着
OAuth2AuthorizationRequestRedirectFilter就能处理该请求,并且进入if语句中进行重定向到认证服务。而设置保存
OAuth2AuthorizationRequest对象到session中就在如下方法中。

this.sendRedirectForAuthorization(request, response, authorizationRequest);

Springboot整合第三方OAuth2登录详解及避坑

保存OAuth2AuthorizationReques对象到session中

Springboot整合第三方OAuth2登录详解及避坑

 

Springboot整合第三方OAuth2登录详解及避坑

从session获取OAuth2AuthorizationReques对象

设置和获取使用的key都是同一个(确保没有错误)

测试session是否真的有东西?我把跳转到认证服务的地址改错,然后请求,接着用另外一个接口打印session中的内容。

Springboot整合第三方OAuth2登录详解及避坑

 

session中是有内容的,接着吧跳转地址改对,再看session中的内容

跳转到登录页面后,不进行登录,接着访问打印session的接口:

Springboot整合第三方OAuth2登录详解及避坑

 

session中已经没有内容了。

证实:session是跳转到了认证服务后就没有了。难道真的是stackoverflow上所说?

Springboot整合第三方OAuth2登录详解及避坑

 

翻译过来就是:

这些错误意味着找不到授权请求.授权请求存储在会话中,因此有些会话未被存储.默认情况下,会话由cookie管理.
所以我认为这可能是因为你在localhost上运行了所有东西,所以第一个cookie由localhost:8080设置来存储授权请求会话数据,&当你登录到localhost:8081时,它会为它的会话设置另一个cookie。(这里经查,cookie同ip不同端口,cookie共享)。

最后来个结果图,能够返回code,有了这个就可以获取token,获取了token就可以获取用户信息,然后将用户信息交由AuthenticationManager管理实现登录。

Springboot整合第三方OAuth2登录详解及避坑

 


解决上面的问题

在c:\windows\System32\drivers\etc\host文件中添加了如下

Springboot整合第三方OAuth2登录详解及避坑

 

让我们的认证服务通过这个域名访问,修改应用配置文件:

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

Springboot整合第三方OAuth2登录详解及避坑

 

2、通过上一步获取的token再自动调用获取用户信息表

Springboot整合第三方OAuth2登录详解及避坑

 

注意:获取用户信息的接口,你应该只验证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

完毕!!!

Springboot整合第三方OAuth2登录详解及避坑

给个关注吧谢谢

Springboot整合第三方OAuth2登录详解及避坑

 

 

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 动态网关配置

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/80016.html

(0)

相关推荐

半码博客——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!