要实现绑定与解绑,首先我们需要知道社交账号的绑定状态,绑定就是重新走一下OAuth2
流程,关联当前登录用户(将系统用户和社交账户绑定),解绑就是删除UserConnection
表数据。Spring Social
默认在ConnectController
类上已经帮我们实现了以上的需求。
获取绑定状态
只有数据没有视图这个要我们根据需求来实现
org.springframework.social.connect.web.ConnectController#connectionStatus
-
/**
-
* Render the status of connections across all providers to the user as HTML in their web browser.
-
* @param request the request
-
* @param model the model
-
* @return the view name of the connection status page for all providers
-
*/
-
@RequestMapping(method=RequestMethod.GET)
-
public String connectionStatus(NativeWebRequest request, Model model) {
-
setNoCache(request);
-
processFlash(request, model);
-
Map<String, List<Connection<?>>> connections = connectionRepository.findAllConnections();
-
model.addAttribute(
"providerIds", connectionFactoryLocator.registeredProviderIds());
-
model.addAttribute(
"connectionMap", connections);
-
return connectView();
-
}
-
-
//返回视图
-
protected String connectView() {
-
return getViewPath() +
"status";
//connect/status
-
}
实现我们的视图展示
-
package com.rui.tiger.auth.core.social;
-
-
import com.alibaba.fastjson.JSON;
-
import org.apache.commons.collections.CollectionUtils;
-
import org.springframework.social.connect.Connection;
-
import org.springframework.stereotype.Component;
-
import org.springframework.web.servlet.view.AbstractView;
-
-
import javax.servlet.http.HttpServletRequest;
-
import javax.servlet.http.HttpServletResponse;
-
import java.util.HashMap;
-
import java.util.List;
-
import java.util.Map;
-
-
/**
-
* 社交账号绑定视图
-
* @author CaiRui
-
* @Date 2019-01-20 10:01
-
*/
-
@Component(
"connect/status")
-
public
class TigerConnectionStatusView 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");
-
//key :社交供应商id value:是否绑定
-
Map<String,Boolean> bindResult=
new HashMap<>();
-
for(String providerId:connections.keySet()){
-
bindResult.put(providerId, CollectionUtils.isNotEmpty(connections.get(providerId)));
-
}
-
response.setContentType(
"application/json;charset=UTF-8");
-
response.getWriter().write(JSON.toJSONString(bindResult));
//返回json
-
}
-
}
绑定
源码如下:
-
/**
-
* Process a connect form submission by commencing the process of establishing a connection to the provider on behalf of the member.
-
* For OAuth1, fetches a new request token from the provider, temporarily stores it in the session, then redirects the member to the provider's site for authorization.
-
* For OAuth2, redirects the user to the provider's site for authorization.
-
* @param providerId the provider ID to connect to
-
* @param request the request
-
* @return a RedirectView to the provider's authorization page or to the connection status page if there is an error
-
*/
-
@RequestMapping(value=
"/{providerId}", method=RequestMethod.POST)
-
public RedirectView connect(@PathVariable String providerId, NativeWebRequest request) {
-
ConnectionFactory<?> connectionFactory = connectionFactoryLocator.getConnectionFactory(providerId);
-
MultiValueMap<String, String> parameters =
new LinkedMultiValueMap<String, String>();
-
preConnect(connectionFactory, parameters, request);
-
try {
-
return
new RedirectView(connectSupport.buildOAuthUrl(connectionFactory, request, parameters));
-
}
catch (Exception e) {
-
sessionStrategy.setAttribute(request, PROVIDER_ERROR_ATTRIBUTE, e);
-
return connectionStatusRedirect(providerId, request);
-
}
-
}
绑定/解绑公用视图
-
package com.rui.tiger.auth.core.social;
-
-
import org.springframework.web.servlet.view.AbstractView;
-
-
import javax.servlet.http.HttpServletRequest;
-
import javax.servlet.http.HttpServletResponse;
-
import java.util.Map;
-
-
/**
-
* 微信wechat社交账号绑定、解绑 成功返回界面 放在配置中管理bean
-
* getViewPath() + providerId + "Connected";// connect/wechat/Connected
-
* @author CaiRui
-
* @Date 2019-01-20 11:19
-
*/
-
public
class TigerConnectView 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(
"connections") ==
null) {
-
response.getWriter().write(
"<h3>解绑成功</h3>");
-
}
else {
-
response.getWriter().write(
"<h3>绑定成功</h3>");
-
}
-
}
-
}
注入绑定结果视图:
-
package com.rui.tiger.auth.core.social.wechat.config;
-
-
import com.rui.tiger.auth.core.properties.SecurityProperties;
-
import com.rui.tiger.auth.core.properties.WechatProperties;
-
import com.rui.tiger.auth.core.social.TigerConnectView;
-
import com.rui.tiger.auth.core.social.wechat.connect.WechatConnectionFactory;
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-
import org.springframework.context.annotation.Bean;
-
import org.springframework.context.annotation.Configuration;
-
import org.springframework.core.env.Environment;
-
import org.springframework.social.config.annotation.ConnectionFactoryConfigurer;
-
import org.springframework.social.config.annotation.SocialConfigurerAdapter;
-
import org.springframework.social.connect.ConnectionFactory;
-
import org.springframework.social.connect.ConnectionFactoryLocator;
-
import org.springframework.social.connect.UsersConnectionRepository;
-
import org.springframework.web.servlet.View;
-
-
/**
-
* 微信登陆配置
-
* @author CaiRui extends SocialConfigurerAdapter
-
* @Date 2019-01-12 13:57
-
*/
-
@Configuration
-
@ConditionalOnProperty(prefix =
"tiger.auth.social.wechat", name =
"app-id")
-
public
class WechatAutoConfiguration extends SocialConfigurerAdapter {
-
@Autowired
-
private SecurityProperties securityProperties;
-
-
@Override
-
public void addConnectionFactories(ConnectionFactoryConfigurer connectionFactoryConfigurer, Environment environment) {
-
connectionFactoryConfigurer.addConnectionFactory(createConnectionFactory());
-
}
-
-
-
-
private ConnectionFactory<?> createConnectionFactory() {
-
WechatProperties weixinConfig = securityProperties.getSocial().getWechat();
-
return
new WechatConnectionFactory(weixinConfig.getProviderId(), weixinConfig.getAppId(),
-
weixinConfig.getAppSecret());
-
}
-
-
/**
-
* 微信绑定解绑界面视图
-
* connect/wechatConnected:绑定
-
* connect/wechatConnect:解绑
-
* @return
-
*/
-
@Bean({
"connect/wechatConnect",
"connect/wechatConnected"})
-
@ConditionalOnMissingBean(name =
"wechatConnectedView")
//可以自定义实现覆盖此默认界面
-
public View wechatConnectedView(){
-
return
new TigerConnectView();
-
}
-
-
-
-
// 后补:做到处理注册逻辑的时候发现的一个bug:登录完成后,数据库没有数据,但是再次登录却不用注册了
-
// 就怀疑是否是在内存中存储了。结果果然发现这里父类的内存ConnectionRepository覆盖了SocialConfig中配置的jdbcConnectionRepository
-
// 这里需要返回null,否则会返回内存的 ConnectionRepository
-
@Override
-
public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
-
return
null;
-
}
-
-
}
标准绑定界面:tiger-auth\tiger-auth-browser\src\main\resources\static\tiger-binding.html
-
<html>
-
<head>
-
<meta charset="UTF-8">
-
<title>绑定
</title>
-
</head>
-
<body>
-
<h2>微信标准绑定页面
</h2>
-
<form action="/connect/wechat" method="post">
-
<button type="submit">绑定微信
</button>
-
</form>
-
-
<h2>QQ标准绑定页面
</h2>
-
<form action="/connect/qq" method="post">
-
<button type="submit">绑定QQ
</button>
-
</form>
-
-
</body>
-
</html>
调试:
调试qq绑定报下面错误
qq获取授权码文档:http://wiki.connect.qq.com/%e4%bd%bf%e7%94%a8authorization_code%e8%8e%b7%e5%8f%96access_token
经过源码分析发现回调地址:
推测要在互联回调地址也要加 /connect/qq 才可以 等待验证。
解绑
源码如下:
-
/**
-
* Remove all provider connections for a user account.
-
* The user has decided they no longer wish to use the service provider from this application.
-
* Note: requires {@link HiddenHttpMethodFilter} to be registered with the '_method' request parameter set to 'DELETE' to convert web browser POSTs to DELETE requests.
-
* @param providerId the provider ID to remove the connections for
-
* @param request the request
-
* @return a RedirectView to the connection status page
-
*/
-
@RequestMapping(value=
"/{providerId}", method=RequestMethod.DELETE)
-
public RedirectView removeConnections(@PathVariable String providerId, NativeWebRequest request) {
-
ConnectionFactory<?> connectionFactory = connectionFactoryLocator.getConnectionFactory(providerId);
-
preDisconnect(connectionFactory, request);
-
connectionRepository.removeConnections(providerId);
-
postDisconnect(connectionFactory, request);
-
return connectionStatusRedirect(providerId, request);
-
}
可以调用postman模拟实现 http://mrcode.cn/connect/qq
文章转载至:https://blog.csdn.net/ahcr1026212/article/details/86550205