【SpringSecurity+OAuth2+JWT入门到实战】23.改造基于APP接口社交注册
简介
上章完成社交登录但是我们是在数据库有用户的情况下登录了,这章解决数据库无该用户数据先完成注册再登录。
流程
看之前浏览器代码如果用户未注册我们会把用户引导到注册页面
注册完成以后访问/social/user连接通过ProviderSignInUtils帮助包到session取用户资料
登录通过以会拿到用户的唯一标识再调用doPostSignUp方法从session拿出用户资料进行绑定再添加到数据库
到这里我们也看到问题那就是整个流程都是基于session完成的,但是我们APP是无session的
改造
改造思路如果第三方信息在数据库查不到数据先保存到Redis等用户注册完我们平台账号拿到userId以后再绑定保存到数据库
创建帮助类AppSingUpUtils:
/** *
*/
package com.spring.security.social;
import java.util.concurrent.TimeUnit;
import com.spring.security.AppSecretException;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.social.connect.Connection;
import org.springframework.social.connect.ConnectionData;
import org.springframework.social.connect.ConnectionFactoryLocator;
import org.springframework.social.connect.UsersConnectionRepository;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.WebRequest;
/**
* app环境下替换providerSignInUtils,避免由于没有session导致读不到社交用户信息的问题
*
*/
@Component
public class AppSingUpUtils {
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Autowired
private UsersConnectionRepository usersConnectionRepository;
@Autowired
private ConnectionFactoryLocator connectionFactoryLocator;
/**
* 缓存社交网站用户信息到redis
* @param request
* @param connectionData
*/
public void saveConnectionData(WebRequest request, ConnectionData connectionData) {
redisTemplate.opsForValue().set(getKey(request), connectionData, 10, TimeUnit.MINUTES);
}
/**
* 将缓存的社交网站用户信息与系统注册用户信息绑定
* @param request
* @param userId
*/
public void doPostSignUp(WebRequest request, String userId) {
String key = getKey(request);
if(!redisTemplate.hasKey(key)){
throw new AppSecretException("无法找到缓存的用户社交账号信息");
}
ConnectionData connectionData = (ConnectionData) redisTemplate.opsForValue().get(key);
Connection<?> connection = connectionFactoryLocator.getConnectionFactory(connectionData.getProviderId())
.createConnection(connectionData);
usersConnectionRepository.createConnectionRepository(userId).addConnection(connection);
redisTemplate.delete(key);
}
/**
* 获取redis key
* @param request
* @return
*/
private String getKey(WebRequest request) {
String deviceId = request.getHeader("deviceId");
if (StringUtils.isBlank(deviceId)) {
throw new AppSecretException("设备id参数不能为空");
}
return "imooc:security:social.connect." + deviceId;
}
}
异常处理
/** *
*/
package com.spring.security;
public class AppSecretException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = -1629364510827838114L;
public AppSecretException(String msg){
super(msg);
}
}
提取hkSocialSecurityConfig类:
package com.spring.security.social;import com.spring.security.properties.SecurityConstants;
import com.spring.security.social.support.HkSpringSocialConfigurer;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class SpringSocialConfigurerPostProcessor implements BeanPostProcessor {
/* (non-Javadoc)
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(StringUtils.equals(beanName, "hkSocialSecurityConfig")){
HkSpringSocialConfigurer config = (HkSpringSocialConfigurer)bean;
config.signupUrl(SecurityConstants.DEFAULT_SOCIAL_USER_INFO_URL);
return config;
}
return bean;
}
}
/*** 获取第三方用户信息的url
*/
String DEFAULT_SOCIAL_USER_INFO_URL = "/social/user";
创建访问/social/user控制层:
/** *
*/
package com.spring.security;
import javax.servlet.http.HttpServletRequest;
import com.spring.security.properties.SecurityConstants;
import com.spring.security.social.AppSingUpUtils;
import com.spring.security.social.support.SocialUserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.social.connect.Connection;
import org.springframework.social.connect.web.ProviderSignInUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.ServletWebRequest;
@RestController
public class AppSecurityController {
@Autowired
private ProviderSignInUtils providerSignInUtils;
@Autowired
private AppSingUpUtils appSingUpUtils;
/**
* 需要注册时跳到这里,返回401和用户信息给前端
* @param request
* @return
*/
@GetMapping(SecurityConstants.DEFAULT_SOCIAL_USER_INFO_URL)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public SocialUserInfo getSocialUserInfo(HttpServletRequest request) {
SocialUserInfo socialUsrInfo = new SocialUserInfo();
Connection<?> connection = providerSignInUtils.getConnectionFromSession(new ServletWebRequest(request));
socialUsrInfo.setProviderId(connection.getKey().getProviderId());
socialUsrInfo.setProviderUserId(connection.getKey().getProviderUserId());
socialUsrInfo.setNickname(connection.getDisplayName());
socialUsrInfo.setHeadimg(connection.getImageUrl());
appSingUpUtils.saveConnectionData(new ServletWebRequest(request), connection.createData());
return socialUsrInfo;
}
}
package com.spring.security.social.support;public class SocialUserInfo {
private String providerId;
private String providerUserId;
private String nickname;
private String headimg;
public String getProviderId() {
return providerId;
}
public void setProviderId(String providerId) {
this.providerId = providerId;
}
public String getProviderUserId() {
return providerUserId;
}
public void setProviderUserId(String providerUserId) {
this.providerUserId = providerUserId;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getHeadimg() {
return headimg;
}
public void setHeadimg(String headimg) {
this.headimg = headimg;
}
}
修改用户绑定方法:
/** * 注册和绑定
*
* @return
*/
@PostMapping("/user/regist")
public void regist(User user, HttpServletRequest request) {
//这里不管是绑定还是添加 我们都会通过查询或者添加返回用户ID 唯一标
//我先用用户名当成唯一标识
String userId = user.getUsername();
appSingUpUtils.doPostSignUp(new ServletWebRequest(request), userId);
}
/user/regist和/social/user需要加到不需要认证配置。
启动项目通过昨天方法拿到:
http://127.0.0.1/auth/qq?code=EC04D3F128C9C0B4926384DAAC1A5DCD&state=8883f264-8eae-4c18-a0fb-9de0c61cbcc9
返回401需要APP用到用户去注册我们平台。
通过/user/regist来绑定用户账号:
点Send返回200,看数据库:
现在通过社交openId和providerId去拿token:
访问数据:
以上是 【SpringSecurity+OAuth2+JWT入门到实战】23.改造基于APP接口社交注册 的全部内容, 来源链接: utcz.com/z/514577.html