spring-security-oauth2(十四 ) 社交账号绑定与解绑

要实现绑定与解绑,首先我们需要知道社交账号的绑定状态,绑定就是重新走一下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

经过源码分析发现回调地址:

https://graph.qq.com/oauth2.0/authorize?client_id=101316278&response_type=code&redirect_uri=http%3A%2F%2Fmrcode.cn%2Fconnect%2Fqq&state=8596e119-5c2a-4f2a-99cc-ec1c8a8aac85

推测要在互联回调地址也要加 /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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值