简介
上一篇文章完成QQ登录,一般操作如果当前QQ登录用户在我们数据库没有注册那应该跳注册绑定页面,如果我们未配置跳转的页面默认会跳转到:/signup
源码分析
进入SocialAuthenticationFilter中
private Authentication doAuthentication(SocialAuthenticationService<?> authService, HttpServletRequest request, SocialAuthenticationToken token) {
try {
if (!authService.getConnectionCardinality().isAuthenticatePossible()) {
return null;
} else {
token.setDetails(this.authenticationDetailsSource.buildDetails(request));
Authentication success = this.getAuthenticationManager().authenticate(token);
Assert.isInstanceOf(SocialUserDetails.class, success.getPrincipal(), "unexpected principle type");
this.updateConnections(authService, token, success);
return success;
}
} catch (BadCredentialsException var5) {
//判断是否设置了注册页面 默认注册页面/signup
if (this.signupUrl != null) {
this.sessionStrategy.setAttribute(new ServletWebRequest(request), ProviderSignInAttempt.SESSION_ATTRIBUTE, new ProviderSignInAttempt(token.getConnection()));
throw new SocialAuthenticationRedirectException(this.buildSignupUrl(request));
} else {
throw var5;
}
}
}
自定义注册页
demo项目先建注册页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>标准注册页面</title>
</head>
<body>
<h2>demo注册页面</h2>
<h3>注册</h3>
<!-- 不管是注册还是绑定都提交到regist -->
<form action="/user/regist" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td colspan="2">
<button type="submit" value="regist">绑定</button>
<button type="submit" value="binding">注册</button>
</td>
</tr>
</table>
</form>
</body>
</html>
修改BrowserProperties类加注册页面的路径
注意要把下面路径加到不需要认证配置
/**
* 注册页面
*/
private String signUpUrl = "/signUp.html";
修改默认的注册页
修改SocialConfig类
@Bean
public SpringSocialConfigurer hkSocialSecurityConfig(){
// 默认配置类,进行组件的组装
// 包括了过滤器SocialAuthenticationFilter 添加到security过滤链中
//自定义登录路径
String filterProcessesUrl = this.securityProperties.getSocil().getFilterProcessesUrl();
HkSpringSocialConfigurer configurer = new HkSpringSocialConfigurer(filterProcessesUrl);
//自定义注册页
configurer.signupUrl(securityProperties.getBrowser().getSignUpUrl());
return configurer;
}
控制层Controller
先写User实体类接收页面传的参数
package com.spring.security.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class User {
//用户ID
private String id;
//用户名
private String username;
//密码
private String password;
}
做/user/regist遇到两个问题:
- 如何从springsocial里取出已QQ登录用户的资料
- 如何在用户点击绑定的时候把数据配置好交给springsocial去添加到数据库
解决从springsocial里取出已QQ登录用户的资料
springsocial帮我们提供了帮助包ProviderSignInUtils
SocialConfig类重写providerSignInUtils方法
//取用户资料
@Bean
public ProviderSignInUtils providerSignInUtils(ConnectionFactoryLocator connectionFactoryLocator) {
return new ProviderSignInUtils(connectionFactoryLocator, getUsersConnectionRepository(connectionFactoryLocator));
}
BrowserSecurityController类添加对外访问的接口
创建返回实体类SocialUserInfo类
package com.spring.security.support;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class SocialUsrInfo {
//应用id
private String providerId;
//用户Id
private String providerUserId;
//用户名称
private String nickname;
//用户头像
private String headimg;
}
BrowserSecurityController类添加方法
@Autowired
private ProviderSignInUtils providerSignInUtils;
/**
* 读取用户springSocial资料
* @return
*/
@GetMapping("/social/user")
public SocialUsrInfo getSocialUsrInfo(HttpServletRequest request){
SocialUsrInfo socialUsrInfo = new SocialUsrInfo();
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());
return socialUsrInfo;
}
this.sessionStrategy.setAttribute(new ServletWebRequest(request), ProviderSignInAttempt.SESSION_ATTRIBUTE, new ProviderSignInAttempt(token.getConnection()));
拦截器在这一步把用户的信息放到session里面
QQ登录成功以后就可以通过/social/user访问springsocial里面的用户资料
如何在用户点击绑定的时候把数据配置好交给springsocial去添加到数据库
package com.spring.security.controller;
import com.spring.security.dto.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.social.connect.web.ProviderSignInUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.ServletWebRequest;
import javax.servlet.http.HttpServletRequest;
@RestController
public class HelloController {
@GetMapping("hello")
public String hello() {
return "hello spring security";
}
@GetMapping("index")
public String index() {
return "登录成功跳转";
}
@GetMapping("failure")
public String failure() {
return "登录失败跳转";
}
@Autowired
private ProviderSignInUtils providerSignInUtils;
/**
* 注册和绑定
*
* @return
*/
@PostMapping("/user/regist")
public void regist(User user, HttpServletRequest request) {
//这里不管是绑定还是添加 我们都会通过查询或者添加返回用户ID 唯一标
//我先用用户名当成唯一标识
String userId = user.getUsername();
providerSignInUtils.doPostSignUp(userId, new ServletWebRequest(request));
}
}
看源码
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Assert.isInstanceOf(SocialAuthenticationToken.class, authentication, "unsupported authentication type");
Assert.isTrue(!authentication.isAuthenticated(), "already authenticated");
SocialAuthenticationToken authToken = (SocialAuthenticationToken) authentication;
String providerId = authToken.getProviderId();
Connection<?> connection = authToken.getConnection();
// 查询数据库是否存在当前第三方数据,不存在就抛异常
// 通过JdbcUsersConnectionRepository查询
String userId = toUserId(connection);
if (userId == null) {
throw new BadCredentialsException("Unknown access token");
}
//如果id不为空则去数据库查询用户信息
UserDetails userDetails = userDetailsService.loadUserByUserId(userId);
if (userDetails == null) {
throw new UsernameNotFoundException("Unknown connected account id");
}
//然后把查询到的信息放到social
return new SocialAuthenticationToken(connection, userDetails, authToken.getProviderAccountData(), getAuthorities(providerId, userDetails));
}
注意要把路径加到不需要认证配置:/user/regist
我的QQ互助联在审核就不测试了,请自行测试。
来源:oschina
链接:https://my.oschina.net/u/1046143/blog/3190571