Spring Security(八):认证(Authentication)-社交登录(Social)-绑定和解绑
一:绑定
当用于已经在平台上注册过账号之后,可以通过绑定将第三方社交账号绑定到平台注册的账号,以后使用第三方社交账号登录即可。
绑定和解绑的原理是在原来的第三方社交登录的基础之上增加了一个org.springframework.social.connect.web.ConnectController类,用于接收绑定和解绑的请求。
二:获取社交账号的绑定结果
MyConnectionStatusView: 连接状态视图,Spring Security Social会获取所有已配置的社交账号的绑定情况,然后调用"connect/status"这个组件,这里是以json的格式输出。
@Component("connect/status")
public class MyConnectionStatusView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
Map<String, List<Connection<?>>> connections = (Map<String, List<Connection<?>>>) model.get("connectionMap");
Map<String, Boolean> result = new HashMap<>();
for (String key : connections.keySet()) {
result.put(key, !CollectionUtils.isEmpty(connections.get(key)));
}
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(JSONObject.toJSONString(result));
}
}
ConnectController 是Spring Security Social已经写好的控制器,请求路径为@RequestMapping("/connect")
@Configuration
@EnableSocial
public class SocialConfiguration extends SocialConfigurerAdapter {
@Bean
public ConnectController connectController(ConnectionFactoryLocator connectionFactoryLocator, ConnectionRepository connectionRepository) {
return new ConnectController(connectionFactoryLocator, connectionRepository);
}
}
- 先访问登录页面 http://xxx.com/login,输入admin/123456进行登录
- 再访问/connect路径 http://xxx.com/connect 获取QQ和Weixin是否已经绑定过,false表示没有绑定过
三:绑定
注意:在引入social相关依赖时不要用1.1.4这个版本,这个版本有严重的bug,缺少方法,这里使用最新的版本1.1.6.RELEASE
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-web</artifactId>
<version>1.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-core</artifactId>
<version>1.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-config</artifactId>
<version>1.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-security</artifactId>
<version>1.1.6.RELEASE</version>
</dependency>
binding.html
这里演示的是QQ绑定,微信绑定和QQ原理一样,只不过发送的地址对应的providerId不一样,绑定的请求的路径为/connect/providerId, QQ 的providerId设置为"callback.do", 所以整体路径为"/connect/callback.do"
<!DOCTYPE html>
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<title>绑定</title>
</head>
<body>
<form action="/connect/callback.do" method="post">
<button type="submit">绑定QQ</button>
</form>
</body>
</html>
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.addViewController("/signup").setViewName("signup");
registry.addViewController("/binding").setViewName("binding");
registry.addViewController("/index").setViewName("index");
}
}
MyConnectedView: 绑定成功的页面视图
public class MyConnectedView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("绑定成功");
}
}
@Configuration
@ConditionalOnProperty(prefix = "social.qq", name = "appId")
@EnableConfigurationProperties(QQProperties.class)
public class QQAutoConfig extends SocialConfigurerAdapter {
/**
* 关于bean的名称spring-social-web不同的版本可能不一样,具体是什么可以通过下面的类打端点看一下
* org.springframework.social.connect.web.ConnectController#connectionStatusRedirect(java.lang.String, org.springframework.web.context.request.NativeWebRequest)
* @return
*/
@Bean("connect/callback.do.doConnect")
public View qqConnectedView() {
return new MyConnectedView();
}
}
@Configuration
@ConditionalOnProperty(prefix = "social.weixin", name = "appId")
@EnableConfigurationProperties(WeixinProperties.class)
public class WeixinAutoConfiguration extends SocialConfigurerAdapter {
/**
* 关于bean的名称spring-social-web不同的版本可能不一样,具体是什么可以通过下面的类打端点看一下
* org.springframework.social.connect.web.ConnectController#connectionStatusRedirect(java.lang.String, org.springframework.web.context.request.NativeWebRequest)
* @return
*/
@Bean("connect/weixin.doConnect")
public View weixinConnectedView() {
return new MyConnectedView();
}
}
网站回调域
注意网站回调域不光要配置filterProcessesUrl/providerId对应的地址,也要配置connect/providerId地址,也就是说网站回调域要配置两个地址,中间都分号分割。如 http://www.example.com/qqLogin/callback.do;http://www.example.com/connect/callback.do
先访问登录页面/login,再访问绑定页面/binding
绑定成功后可以看到UserConnection表的userid变成了登录时使用的用户名
四:解绑
绑定和解绑使用同一个视图
public class MyConnectedView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
response.setContentType("text/html;charset=UTF-8");
if (model.get("connection") == null) {
response.getWriter().write("绑定成功");
} else {
response.getWriter().write("解绑成功");
}
}
}
@Configuration
@ConditionalOnProperty(prefix = "social.qq", name = "appId")
@EnableConfigurationProperties(QQProperties.class)
public class QQAutoConfig extends SocialConfigurerAdapter {
/**
* 关于bean的名称spring-social-web不同的版本可能不一样,具体是什么可以通过下面的类打端点看一下
* org.springframework.social.connect.web.ConnectController#connectionStatusRedirect(java.lang.String, org.springframework.web.context.request.NativeWebRequest)
* @return
*/
@Bean({"connect/callback.do.doConnect", "connect/callback.doConnected"})
public View qqConnectedView() {
return new MyConnectedView();
}
}
@Configuration
@ConditionalOnProperty(prefix = "social.weixin", name = "appId")
@EnableConfigurationProperties(WeixinProperties.class)
public class WeixinAutoConfiguration extends SocialConfigurerAdapter {
/**
* 关于bean的名称spring-social-web不同的版本可能不一样,具体是什么可以通过下面的类打端点看一下
* org.springframework.social.connect.web.ConnectController#connectionStatusRedirect(java.lang.String, org.springframework.web.context.request.NativeWebRequest)
* @return
*/
@Bean({"connect/weixin.doConnect", "connect/weixin.doConnected"})
public View weixinConnectedView() {
return new MyConnectedView();
}
}
使用Chrome插件Restlet Client发送解绑请求,请求方式为Delete
解绑后UserConnection表之前userid=admin的这条数据没有了
上一篇: 脱毛安全比美重要 别让美影响健康