当前位置: 首页 > news >正文

SpringSecurity随笔(2)-OAuth2协议

短信登录

参考密码登录过程

1.编写短信登录过滤器,验证短信验证码
2.编写未认证得SmsAuthenticationToken
3.将未认证的SmsAuthenticationToken传递给AuthenticationManager
4.编写一个SmsAuthenticationProvider
5.调用UserDetialsService获取用户信息

OAuth协议

OAUTH协议为用户资源的授权提供了一个安全的、开放而又简易的标准。

认证服务器:认证用户身份,生成令牌。 资源服务器:保存用户资源,验证令牌。

授权模式

1.授权码模式
2.密码模式
3.客户端模式
4.简化模式

授权码模式

Spring Social

核心组件

OAuth2Template:OAuth协议核心流程的封装

AbstractOAuth2ApiBinding:不同服务提供商的用户信息

OAuth2Connection:封装获取到的用户信息

OAuth2ConnectionFactory:创建OAuth2Connection实例

ServiceProvider:调用OAuth2Template获取用户信息

ApiAdapter:将获取的用户信息封装为标准的OAuth2Connection

UsersConnectionRepository:应用用户信息和服务提供商用户信息的映射

SpringSocial组件

SpringSocialConfigurer:核心配置组件

SpringSocialConfigurer#configure:创建SocialAuthenticationFilter

1.org.springframework.social.security.provider.OAuth2AuthenticationService#getAuthToken 取授权码

public SocialAuthenticationToken getAuthToken(HttpServletRequest request, HttpServletResponse response) throws SocialAuthenticationRedirectException {//获取授权码
		String code = request.getParameter("code");
		//授权码为空 导向认证服务器,获取授权码
		if (!StringUtils.hasText(code)) {
			OAuth2Parameters params =new OAuth2Parameters();
			params.setRedirectUri(buildReturnToUrl(request));
			setScope(request, params);
			params.add("state", generateState(connectionFactory, request));
			addCustomParameters(params);
			throw new SocialAuthenticationRedirectException(getConnectionFactory().getOAuthOperations().buildAuthenticateUrl(params)); // 拼URL
			// 拿这授权码换令牌
		} else if (StringUtils.hasText(code)) {
			try {
				String returnToUrl = buildReturnToUrl(request);
				// 获取token
				AccessGrant accessGrant = getConnectionFactory().getOAuthOperations().exchangeForAccess(code, returnToUrl, null);
				// TODO avoid API call if possible (auth using token would be fine)
				Connection<S> connection = getConnectionFactory().createConnection(accessGrant);
				return new SocialAuthenticationToken(connection, null);
			} catch (RestClientException e) {
				logger.debug("failed to exchange for access", e);
				return null;
			}
		} else {
			return null;
		}
	} 

2.org.springframework.social.oauth2.OAuth2Template#exchangeForAccess 取token

public AccessGrant exchangeForAccess(String authorizationCode, String redirectUri, MultiValueMap<String, String> additionalParameters) {
		MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
		if (useParametersForClientAuthentication) {
			params.set("client_id", clientId);
			params.set("client_secret", clientSecret);
		}
		params.set("code", authorizationCode);
		params.set("redirect_uri", redirectUri);
		params.set("grant_type", "authorization_code");
		if (additionalParameters != null) {
			params.putAll(additionalParameters);
		}
		return postForAccessGrant(accessTokenUrl, params);
 }
//取toknen json格式 
protected AccessGrant postForAccessGrant(String accessTokenUrl, MultiValueMap<String, String> parameters) {
		return extractAccessGrant(getRestTemplate().postForObject(accessTokenUrl, parameters, Map.class));
 } 

3.创建RestTemplate模板

protected RestTemplate createRestTemplate() {
		ClientHttpRequestFactory requestFactory = ClientHttpRequestFactorySelector.getRequestFactory();
		RestTemplate restTemplate = new RestTemplate(requestFactory);
		List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>(2);
		converters.add(new FormHttpMessageConverter());
		converters.add(new FormMapHttpMessageConverter());
		converters.add(new MappingJackson2HttpMessageConverter());
		restTemplate.setMessageConverters(converters);
		restTemplate.setErrorHandler(new LoggingErrorHandler());
		if (!useParametersForClientAuthentication) {
			List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
			if (interceptors == null) { // defensively initialize list if it is null. (See SOCIAL-430)
				interceptors = new ArrayList<ClientHttpRequestInterceptor>();
				restTemplate.setInterceptors(interceptors);
			}
			interceptors.add(new PreemptiveBasicAuthClientHttpRequestInterceptor(clientId, clientSecret));
		}
		return restTemplate;
	} 

4.重写org.springframework.social.oauth2.OAuth2Template#postForAccessGrant,定制AccessGrant5.org.springframework.social.security.SocialAuthenticationProvider#authenticate 获取到qq用户信息,进行权限认证

org.springframework.social.security.SocialAuthenticationFilter#doAuthentication

QQ登录和微信登录的不同之处,QQ是拿到accessToken用accessToken去换openId,微信在返回accessToken的同时会返回opendId。

QQ在申请授权码的时候通过OAuth2Template#buildAuthenticateUrl(OAuth2Parameters)拼装了URL

例如:https://graph.qq.com/oauth2.0/authorize? client_id=101087& response_type=code& redirect_uri=http://www.sdasda.cn/qqLogin/qq& state=9c103c5a-34a8-4bf5-82df-c0eca91e8f4a

微信的授权码url不是OAuth2标准的

相关文章:

  • 基于Java+SpringBoot+Vue在线培训考试系统设计与实现
  • 【云原生】k8s 一键部署(ansible)
  • mysql:浅显易懂——存储引擎
  • 【鸟哥杂谈】腾讯云 CentOS8 Linux环境下通过docker安装mysql
  • 微服务间通讯负载均衡以及日志
  • 手写拖动上传组件(Vue3/React)
  • 经济学学习(宏观)
  • Android入门第58天-真机调试
  • 【信管9.1】​项目沟通及过程
  • 《Linux Shell脚本攻略》学习笔记-第十章
  • 工作流代码
  • 使用批处理__更改ip
  • 第一章 TCP/IP 协议
  • 前端面试当中 js原型及原型链常考知识点
  • 【代码随想录】343. 整数拆分
  • 使用nginx搭建HTTP FLV流媒体服务器
  • 11 Java接口(语法、规范、微观宏观接口)
  • 前端学习路线(包括计算机基础,算法,项目开发等学习路径)
  • 实战18:基于深度学习的人脸识系统(完整代码+数据+报告+可作为毕设)
  • Vue 2.x源码学习:数据响应式改造