spring security 浏览器第三方登录

OAuth 协议

1、概要简介

服务器提供商不提供账号密码的情况下,通过发放令牌,让第三方应用可以进行认证、授权并访问资源

(1)采用账号密码登录第三方在这里插入图片描述
弊端
① 应用可以访问用户在微信上的所有数据
② 用户只有修改密码,才能收回权限
③ 密码泄露的可能性大大提高

(2)采用令牌登录(OAuth协议)
在这里插入图片描述
在这里插入图片描述

2、四种授权模式

(1)授权码模式(authorization code)
在这里插入图片描述

(2)密码模式(resource owner password credentials)
(3)简化模式(implicit)
(4)客户端模式(client credentials)

3、spring social基本原理

在这里插入图片描述
将以上流程封装成socialAuthenticationFilter过滤器,并加入到过滤链中
在这里插入图片描述

4、使用spring social实现第三方登录

在这里插入图片描述
(1)ConnectFactory:通过ServiceProvider、ApiAdapter创建Connection(OAuth2Connection),保存服务提供商里的用户信息
(2)ServiceProvider:认证、授权,获取授权码并通过其获取令牌(assess_token),传入API实现类中,获取用户信息
(3)Api(AbstractOAuth2ApiBinding)实现:通过传入的accessToken,使用restTemplate发送Http请求换取openId,两者结合appId,获取服务提供商的用户信息
(4)ApiAdapter:将获取用户信息根据标准结构存储到Connection中
(5)UsersConnectionRespiratory(存储器):根据connection中的openId查询对应的userId,通过userId传入SocialUserDetailsService获取SocialUserDetails,构建认证成功的token

5、QQ第三方登录源码解析

在这里插入图片描述
(1)SocialAuthenticationFilter 过滤器拦截:拦截 /auth/qq 请求,第一段 /auth 在过滤器中配置,第二段 /qq 则由QQAutoConfig初始化ConnectionFactory的provider指定
① 拦截未生效,检查SocialConfig、QQAutoConfig(指定的prefix是否正确)
② redirect uri is illegal报错解决,项目回调地址与注册的回调地址不一致造成:

  • hosts文件修改,将127.0.0.1 指向 www.pinzhi365.com
  • SpringSocialConfigurer 在将SocialAuthenticationFilter添加到过滤链前执行了postProcess()方法,通过自定义类继承SpringSocialConfigurer,并覆盖postProcess()方法,实现 /auth 前缀修改
  • SocialAuthticationFilter 配置修改:传入自定义的url,并返回自定继承SpringSocialConfigurer的类

(2)SocialAuthenticationFilter attemptAuthentication方法() --> attemptAuthService() 方法换取token令牌 – > attemptAuthService() 方法调用 authService.getAuthToken()方法 – > OAuth2AuthenticationService 类 中的getAuthToken()方法,判断回调的路径是否有授权码,没有授权码则会抛出SocialAuthenticationRedirectException异常;有授权码,则调用ConnectFactory工程类的ServiceProvide–> getOAuthOperationsr(Oauth2Template)–> exchangeForAccess() 方法进行认证、授权,换取token令牌
① 授权后跳转到signIn页面,报 你访问的页面不存在!错误:

  • attemptAuthService --> Oauth2Template发送http请求,期望返回格式为application/json,但实际返回的是text/html --> attemptAuthService 无法获取token,返回null,抛AuthenticationServiceException异常
  • AbstractAuthenticationProcessingFilter捕获异常 --> 进入失败处理器 unsuccessfulAuthentication --> 调用失败处理器 ailureHandler.onAuthenticationFailure()
  • SocialAuthenticationFilter失败处理器SimpleUrlAuthenticationFailureHandler --> 将应用重定向到DEFAULT_FAILURE_URL --> /signin

② 替换默认的Oauth2Template,写一个自己的实现:

  • 重写 createTemplate() 方法:继承父类,添加一个新的Converters
  • 重写postForAccessGrant() 方法:此方法发送http请求,默认获取的是json格式结果,但qq认证、授权后返回的结果是字符串,故需要重写

③ ServiceProvider 配置文件更改:返回自己定义的Oauth2Template类

(3) SocialAuthenticationFilter getAuthToken()方法获取token令牌后,将调用工程类创建connection,并new一个SocialAuthenticationToken,将connection存入里边
① API实现类,使用token令牌换取OpenId:

  • 获取openId失败,看截取的代码是否有误

② 使用token、openId、appId获取用户信息

(4)SocialAuthenticationFilter的doAuthentication()方法进行 AuthenticationManager(ProviderManager)验证,根据Token选取的对应的AuthenticationProvider,这里对应的是SocialAuthenticationProvider
① authenticate 中调用 toUserId() 方法,根据connection中的providerUserId 调用UsersConnectionRespiratory 获取 对应的userId

  • 若数据库中没有对应记录,获取userId为空,则会抛出BadCredentialsException异常
  • 判断注册url是否为空,默认的为/signup,将会跳转到此页面进行注册

② 注册页创建,注册逻辑自己定义

  • 自定义注册页配置,在SocialAuthticationFilter配置中添加
  • 获取社交账号信息,确认唯一的userId:使用springSocial提供ProviderSignInUtils工具类,需要在socialConfig文件中配置(ProviderSignInUtils可在session中获取用户信息,用户信息又是在什么时候放入session的?–> BadCredentialsException异常跳转到注册页前调用了sessionStrategy.setAttribute()方法)
  • 获取设计账号信息接口:在BrowserSecurityController中创建,需要创建社交账号bean类
  • 自定义注册接口

(5)注册成功后问题收集:
① 再次登录跳转回注册页问题

  • 由于spring版本不同,可能SocialConfig配置被QQAutoConfig配置覆盖,在SocialConfig配置中加入@Order(10)注解

② 登录成功后,自定义跳转页面配置:

  • 在浏览器配置引入社交配置文件后,设置postLoginUrl路径

③ 关于/social/user getSocialUserInfo()接口报connection为空的异常:

  • 此方法只使用于跳转到注册页的时候使用,因为filter拦截获取userId为空,会报异常,而session只有在异常的时候才添加,其他时候都无session,故调用getConnectionFromSession()方法获取不到connection,所以为空,就会抛异常

(6)根据业务场景,有些需求需要使用社交账号后,自动注册,然后跳到成功页面,实现原理、流程如下:
① 由于JdbcUsersConnectionRepository的findUserIdsWithConnection()方法,默认调用了connectionSignUp,所以只需重写此类,进行自动注册即可
② 在socialConfig配置文件中getUsersConnectionRepository()方法进行配置

6、绑定与解绑

(1)自定义一个绑定、解绑标准页面
(2)spring social默认提供相关的接口方法
① 获取第三方绑定情况接口 /connect :

  • 调用ConnectController类 --> connectStatus() 方法 --> connectView() --> 访问 /connect/status 请求
  • 404错误 --> 视图找不到错误解决: 自己写一个connectionStatusView 继承 abstractView

② 绑定第三方接口 /connect/{providerId} 发送post请求: 扫码后绑定成功

  • 绑定成功,返回404页面:访问 /connect/weixinConnected
  • 写一个通用视图 继承 abstractView
  • 在微信配置文件 WeixinAutoConfig 等第三方配置文件,设置返回的视图

③ 解绑第三方接口 /connect/{providerId} 发送delete请求: 直接进行解绑操作

  • 解绑成功,返回404页面:访问 /connect/weixinConnect
  • 写一个通用视图 继承 abstractView
  • 在微信配置文件 WeixinAutoConfig 等第三方配置文件,设置返回的视图
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值