前后端分离项目 — SpringSocial 绑定与解绑社交账号如微信、QQ

<p><code></p> <h1 id="articleHeader0">1、准备工作</h1> <p>申请QQ、微信相关AppId和AppSecret,这些大家自己到<a href="https://connect.qq.com/index.html" rel="nofollow noreferrer" target="_blank">QQ互联</a>和<a href="https://open.weixin.qq.com/cgi-bin/index" rel="nofollow noreferrer" target="_blank">微信开发平台</a> 去申请吧<br /> 还有java后台要引入相关的jar包,如下:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text=" <dependencies> <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>2.3.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!--<dependency>--> <!--<groupId>org.springframework.cloud</groupId>--> <!--<artifactId>spring-cloud-starter-security</artifactId>--> <!--</dependency>--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </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-core</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> <dependency> <groupId>org.springframework.social</groupId> <artifactId>spring-social-web</artifactId> <version>1.1.6.RELEASE</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.7</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.2</version> </dependency> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.3</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-mongodb</artifactId> <version>2.0.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> <version>2.0.4.RELEASE</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.6</version> </dependency>" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code> <span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.security.oauth.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-security-oauth2-autoconfigure<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.security.oauth<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-security-oauth2<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.3.3.RELEASE<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-security<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-comment">&lt;!--&lt;dependency&gt;--&gt;</span> <span class="hljs-comment">&lt;!--&lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;--&gt;</span> <span class="hljs-comment">&lt;!--&lt;artifactId&gt;spring-cloud-starter-security&lt;/artifactId&gt;--&gt;</span> <span class="hljs-comment">&lt;!--&lt;/dependency&gt;--&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.cloud<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-cloud-starter-security<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.cloud<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-cloud-starter-oauth2<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-data-redis<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-jdbc<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>mysql<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mysql-connector-java<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.social<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-social-config<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.1.6.RELEASE<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.social<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-social-core<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.1.6.RELEASE<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.social<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-social-security<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.1.6.RELEASE<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.social<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-social-web<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.1.6.RELEASE<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>io.jsonwebtoken<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>jjwt<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.9.1<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.commons<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>commons-lang3<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.7<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.commons<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>commons-collections4<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>4.2<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>commons-beanutils<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>commons-beanutils<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.9.3<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-configuration-processor<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.data<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-data-mongodb<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.0.9.RELEASE<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-data-mongodb<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.0.4.RELEASE<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.fasterxml.jackson.core<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>jackson-core<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.9.6<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span></code></pre> <p>然后在application.properties里面设置相关配置,如redis、mysql等设置,如下:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text=" spring.datasource.url= spring.datasource.username= spring.datasource.password= spring.datasource.driverClassName=com.mysql.jdbc.Driver spring.redis.host=127.0.0.1 spring.redis.password=your_pwd spring.redis.port=6379 spring.redis.timeout=30000 ssb.security.social.register-url=/social/signUp ssb.security.social.filter-processes-url=/social-login ssb.security.social.bind-url=https://website/social-bind/qq ssb.security.social.callback-url=https://website/social-login ssb.security.social.connect-url=https://website/social-connect //QQ授权 ssb.security.social.qq.app-id= ssb.security.social.qq.app-secret= ssb.security.social.qq.provider-id=qq //WeChat授权 ssb.security.social.wechat.app-id= ssb.security.social.wechat.app-secret= ssb.security.social.wechat.provider-id=wechat" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs objectivec"><code> spring.datasource.url= spring.datasource.username= spring.datasource.password= spring.datasource.driverClassName=com.mysql.jdbc.Driver spring.redis.host=<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span> spring.redis.password=your_pwd spring.redis.port=<span class="hljs-number">6379</span> spring.redis.timeout=<span class="hljs-number">30000</span> ssb.security.social.register-url=/social/signUp ssb.security.social.filter-processes-url=/social-login ssb.security.social.bind-url=https:<span class="hljs-comment">//website/social-bind/qq</span> ssb.security.social.callback-url=https:<span class="hljs-comment">//website/social-login</span> ssb.security.social.connect-url=https:<span class="hljs-comment">//website/social-connect</span> <span class="hljs-comment">//QQ授权</span> ssb.security.social.qq.app-<span class="hljs-keyword">id</span>= ssb.security.social.qq.app-secret= ssb.security.social.qq.provider-<span class="hljs-keyword">id</span>=qq <span class="hljs-comment">//WeChat授权</span> ssb.security.social.wechat.app-<span class="hljs-keyword">id</span>= ssb.security.social.wechat.app-secret= ssb.security.social.wechat.provider-<span class="hljs-keyword">id</span>=wechat</code></pre> <h1 id="articleHeader1">2、分析社交绑定ConnectController类</h1> <p>准备工作做好之后,现在我们开始分析社交绑定,其实spring-social框架里已经自带了spring-social-web,这个jar包里面有个ConnectController.java类,这个类已经帮我们实现了相关绑定与解绑实现方法,问题在于它是基于Session的,所以如果是前后端分离项目使用Session当然应有问题,所以我们要结合Redis来使用,把相关变量都存在Redis中,所以我们上面已经配置好了Redis,我们再来看看Redis配置代码:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="@Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate(ClientHttpRequestFactory factory){ return new RestTemplate(factory); } @Bean public ClientHttpRequestFactory simpleClientHttpRequestFactory(){ SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); factory.setReadTimeout(50000);//单位为ms factory.setConnectTimeout(50000);//单位为ms return factory; } } " title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs dart"><code><span class="hljs-meta">@Configuration</span> public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RestTemplateConfig</span> </span>{ <span class="hljs-meta">@Bean</span> public RestTemplate restTemplate(ClientHttpRequestFactory <span class="hljs-keyword">factory</span>){ <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> RestTemplate(<span class="hljs-keyword">factory</span>); } <span class="hljs-meta">@Bean</span> public ClientHttpRequestFactory simpleClientHttpRequestFactory(){ SimpleClientHttpRequestFactory <span class="hljs-keyword">factory</span> = <span class="hljs-keyword">new</span> SimpleClientHttpRequestFactory(); <span class="hljs-keyword">factory</span>.setReadTimeout(<span class="hljs-number">50000</span>);<span class="hljs-comment">//单位为ms</span> <span class="hljs-keyword">factory</span>.setConnectTimeout(<span class="hljs-number">50000</span>);<span class="hljs-comment">//单位为ms</span> <span class="hljs-keyword">return</span> <span class="hljs-keyword">factory</span>; } } </code></pre> <h1 id="articleHeader2">3、获取系统当前用户所有社交账号绑定情况</h1> <p>设置好之后,我们来分析一下spring-social-web这个jar包获取社交账号绑定情况,它的请求地址是/connect,代码如下:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="@Controller @RequestMapping({&quot;/connect&quot;}) public class ConnectController implements InitializingBean { private static final Log logger = LogFactory.getLog(ConnectController.class); private final ConnectionFactoryLocator connectionFactoryLocator; private final ConnectionRepository connectionRepository; private final MultiValueMap<Class<?>, ConnectInterceptor<?>> connectInterceptors = new LinkedMultiValueMap(); private final MultiValueMap<Class<?>, DisconnectInterceptor<?>> disconnectInterceptors = new LinkedMultiValueMap(); private ConnectSupport connectSupport; private final UrlPathHelper urlPathHelper = new UrlPathHelper(); private String viewPath = &quot;connect/&quot;; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); private String applicationUrl = null; protected static final String DUPLICATE_CONNECTION_ATTRIBUTE = &quot;social_addConnection_duplicate&quot;; protected static final String PROVIDER_ERROR_ATTRIBUTE = &quot;social_provider_error&quot;; protected static final String AUTHORIZATION_ERROR_ATTRIBUTE = &quot;social_authorization_error&quot;; @Inject public ConnectController(ConnectionFactoryLocator connectionFactoryLocator, ConnectionRepository connectionRepository) { this.connectionFactoryLocator = connectionFactoryLocator; this.connectionRepository = connectionRepository; } /** @deprecated */ @Deprecated public void setInterceptors(List<ConnectInterceptor<?>> interceptors) { this.setConnectInterceptors(interceptors); } public void setConnectInterceptors(List<ConnectInterceptor<?>> interceptors) { Iterator var2 = interceptors.iterator(); while(var2.hasNext()) { ConnectInterceptor<?> interceptor = (ConnectInterceptor)var2.next(); this.addInterceptor(interceptor); } } public void setDisconnectInterceptors(List<DisconnectInterceptor<?>> interceptors) { Iterator var2 = interceptors.iterator(); while(var2.hasNext()) { DisconnectInterceptor<?> interceptor = (DisconnectInterceptor)var2.next(); this.addDisconnectInterceptor(interceptor); } } public void setApplicationUrl(String applicationUrl) { this.applicationUrl = applicationUrl; } public void setViewPath(String viewPath) { this.viewPath = viewPath; } public void setSessionStrategy(SessionStrategy sessionStrategy) { this.sessionStrategy = sessionStrategy; } public void addInterceptor(ConnectInterceptor<?> interceptor) { Class<?> serviceApiType = GenericTypeResolver.resolveTypeArgument(interceptor.getClass(), ConnectInterceptor.class); this.connectInterceptors.add(serviceApiType, interceptor); } public void addDisconnectInterceptor(DisconnectInterceptor<?> interceptor) { Class<?> serviceApiType = GenericTypeResolver.resolveTypeArgument(interceptor.getClass(), DisconnectInterceptor.class); this.disconnectInterceptors.add(serviceApiType, interceptor); } @RequestMapping( method = {RequestMethod.GET} ) public String connectionStatus(NativeWebRequest request, Model model) { this.setNoCache(request); this.processFlash(request, model); Map<String, List<Connection<?>>> connections = this.connectionRepository.findAllConnections(); model.addAttribute(&quot;providerIds&quot;, this.connectionFactoryLocator.registeredProviderIds()); model.addAttribute(&quot;connectionMap&quot;, connections); return this.connectView(); } @RequestMapping( value = {&quot;/{providerId}&quot;}, method = {RequestMethod.GET} ) public String connectionStatus(@PathVariable String providerId, NativeWebRequest request, Model model) { this.setNoCache(request); this.processFlash(request, model); List<Connection<?>> connections = this.connectionRepository.findConnections(providerId); this.setNoCache(request); if(connections.isEmpty()) { return this.connectView(providerId); } else { model.addAttribute(&quot;connections&quot;, connections); return this.connectedView(providerId); } } @RequestMapping( value = {&quot;/{providerId}&quot;}, method = {RequestMethod.POST} ) public RedirectView connect(@PathVariable String providerId, NativeWebRequest request) { ConnectionFactory<?> connectionFactory = this.connectionFactoryLocator.getConnectionFactory(providerId); MultiValueMap<String, String> parameters = new LinkedMultiValueMap(); this.preConnect(connectionFactory, parameters, request); try { return new RedirectView(this.connectSupport.buildOAuthUrl(connectionFactory, request, parameters)); } catch (Exception var6) { this.sessionStrategy.setAttribute(request, &quot;social_provider_error&quot;, var6); return this.connectionStatusRedirect(providerId, request); } } @RequestMapping( value = {&quot;/{providerId}&quot;}, method = {RequestMethod.GET}, params = {&quot;oauth_token&quot;} ) public RedirectView oauth1Callback(@PathVariable String providerId, NativeWebRequest request) { try { OAuth1ConnectionFactory<?> connectionFactory = (OAuth1ConnectionFactory)this.connectionFactoryLocator.getConnectionFactory(providerId); Connection<?> connection = this.connectSupport.completeConnection(connectionFactory, request); this.addConnection(connection, connectionFactory, request); } catch (Exception var5) { this.sessionStrategy.setAttribute(request, &quot;social_provider_error&quot;, var5); logger.warn(&quot;Exception while handling OAuth1 callback (&quot; + var5.getMessage() + &quot;). Redirecting to &quot; + providerId + &quot; connection status page.&quot;); } return this.connectionStatusRedirect(providerId, request); } @RequestMapping( value = {&quot;/{providerId}&quot;}, method = {RequestMethod.GET}, params = {&quot;code&quot;} ) public RedirectView oauth2Callback(@PathVariable String providerId, NativeWebRequest request) { try { OAuth2ConnectionFactory<?> connectionFactory = (OAuth2ConnectionFactory)this.connectionFactoryLocator.getConnectionFactory(providerId); Connection<?> connection = this.connectSupport.completeConnection(connectionFactory, request); this.addConnection(connection, connectionFactory, request); } catch (Exception var5) { this.sessionStrategy.setAttribute(request, &quot;social_provider_error&quot;, var5); logger.warn(&quot;Exception while handling OAuth2 callback (&quot; + var5.getMessage() + &quot;). Redirecting to &quot; + providerId + &quot; connection status page.&quot;); } return this.connectionStatusRedirect(providerId, request); } @RequestMapping( value = {&quot;/{providerId}&quot;}, method = {RequestMethod.GET}, params = {&quot;error&quot;} ) public RedirectView oauth2ErrorCallback(@PathVariable String providerId, @RequestParam(&quot;error&quot;) String error, @RequestParam(value = &quot;error_description&quot;,required = false) String errorDescription, @RequestParam(value = &quot;error_uri&quot;,required = false) String errorUri, NativeWebRequest request) { Map<String, String> errorMap = new HashMap(); errorMap.put(&quot;error&quot;, error); if(errorDescription != null) { errorMap.put(&quot;errorDescription&quot;, errorDescription); } if(errorUri != null) { errorMap.put(&quot;errorUri&quot;, errorUri); } this.sessionStrategy.setAttribute(request, &quot;social_authorization_error&quot;, errorMap); return this.connectionStatusRedirect(providerId, request); } @RequestMapping( value = {&quot;/{providerId}&quot;}, method = {RequestMethod.DELETE} ) public RedirectView removeConnections(@PathVariable String providerId, NativeWebRequest request) { ConnectionFactory<?> connectionFactory = this.connectionFactoryLocator.getConnectionFactory(providerId); this.preDisconnect(connectionFactory, request); this.connectionRepository.removeConnections(providerId); this.postDisconnect(connectionFactory, request); return this.connectionStatusRedirect(providerId, request); } @RequestMapping( value = {&quot;/{providerId}/{providerUserId}&quot;}, method = {RequestMethod.DELETE} ) public RedirectView removeConnection(@PathVariable String providerId, @PathVariable String providerUserId, NativeWebRequest request) { ConnectionFactory<?> connectionFactory = this.connectionFactoryLocator.getConnectionFactory(providerId); this.preDisconnect(connectionFactory, request); this.connectionRepository.removeConnection(new ConnectionKey(providerId, providerUserId)); this.postDisconnect(connectionFactory, request); return this.connectionStatusRedirect(providerId, request); } protected String connectView() { return this.getViewPath() + &quot;status&quot;; } protected String connectView(String providerId) { return this.getViewPath() + providerId + &quot;Connect&quot;; } protected String connectedView(String providerId) { return this.getViewPath() + providerId + &quot;Connected&quot;; } protected RedirectView connectionStatusRedirect(String providerId, NativeWebRequest request) { HttpServletRequest servletRequest = (HttpServletRequest)request.getNativeRequest(HttpServletRequest.class); String path = &quot;/connect/&quot; + providerId + this.getPathExtension(servletRequest); if(this.prependServletPath(servletRequest)) { path = servletRequest.getServletPath() + path; } return new RedirectView(path, true); } public void afterPropertiesSet() throws Exception { this.connectSupport = new ConnectSupport(this.sessionStrategy); if(this.applicationUrl != null) { this.connectSupport.setApplicationUrl(this.applicationUrl); } } private boolean prependServletPath(HttpServletRequest request) { return !this.urlPathHelper.getPathWithinServletMapping(request).equals(&quot;&quot;); } private String getPathExtension(HttpServletRequest request) { String fileName = this.extractFullFilenameFromUrlPath(request.getRequestURI()); String extension = StringUtils.getFilenameExtension(fileName); return extension != null?&quot;.&quot; + extension:&quot;&quot;; } private String extractFullFilenameFromUrlPath(String urlPath) { int end = urlPath.indexOf(63); if(end == -1) { end = urlPath.indexOf(35); if(end == -1) { end = urlPath.length(); } } int begin = urlPath.lastIndexOf(47, end) + 1; int paramIndex = urlPath.indexOf(59, begin); end = paramIndex != -1 &amp;&amp; paramIndex < end?paramIndex:end; return urlPath.substring(begin, end); } private String getViewPath() { return this.viewPath; } private void addConnection(Connection<?> connection, ConnectionFactory<?> connectionFactory, WebRequest request) { try { this.connectionRepository.addConnection(connection); this.postConnect(connectionFactory, connection, request); } catch (DuplicateConnectionException var5) { this.sessionStrategy.setAttribute(request, &quot;social_addConnection_duplicate&quot;, var5); } } private void preConnect(ConnectionFactory<?> connectionFactory, MultiValueMap<String, String> parameters, WebRequest request) { Iterator var4 = this.interceptingConnectionsTo(connectionFactory).iterator(); while(var4.hasNext()) { ConnectInterceptor interceptor = (ConnectInterceptor)var4.next(); interceptor.preConnect(connectionFactory, parameters, request); } } private void postConnect(ConnectionFactory<?> connectionFactory, Connection<?> connection, WebRequest request) { Iterator var4 = this.interceptingConnectionsTo(connectionFactory).iterator(); while(var4.hasNext()) { ConnectInterceptor interceptor = (ConnectInterceptor)var4.next(); interceptor.postConnect(connection, request); } } private void preDisconnect(ConnectionFactory<?> connectionFactory, WebRequest request) { Iterator var3 = this.interceptingDisconnectionsTo(connectionFactory).iterator(); while(var3.hasNext()) { DisconnectInterceptor interceptor = (DisconnectInterceptor)var3.next(); interceptor.preDisconnect(connectionFactory, request); } } private void postDisconnect(ConnectionFactory<?> connectionFactory, WebRequest request) { Iterator var3 = this.interceptingDisconnectionsTo(connectionFactory).iterator(); while(var3.hasNext()) { DisconnectInterceptor interceptor = (DisconnectInterceptor)var3.next(); interceptor.postDisconnect(connectionFactory, request); } } private List<ConnectInterceptor<?>> interceptingConnectionsTo(ConnectionFactory<?> connectionFactory) { Class<?> serviceType = GenericTypeResolver.resolveTypeArgument(connectionFactory.getClass(), ConnectionFactory.class); List<ConnectInterceptor<?>> typedInterceptors = (List)this.connectInterceptors.get(serviceType); if(typedInterceptors == null) { typedInterceptors = Collections.emptyList(); } return typedInterceptors; } private List<DisconnectInterceptor<?>> interceptingDisconnectionsTo(ConnectionFactory<?> connectionFactory) { Class<?> serviceType = GenericTypeResolver.resolveTypeArgument(connectionFactory.getClass(), ConnectionFactory.class); List<DisconnectInterceptor<?>> typedInterceptors = (List)this.disconnectInterceptors.get(serviceType); if(typedInterceptors == null) { typedInterceptors = Collections.emptyList(); } return typedInterceptors; } private void processFlash(WebRequest request, Model model) { this.convertSessionAttributeToModelAttribute(&quot;social_addConnection_duplicate&quot;, request, model); this.convertSessionAttributeToModelAttribute(&quot;social_provider_error&quot;, request, model); model.addAttribute(&quot;social_authorization_error&quot;, this.sessionStrategy.getAttribute(request, &quot;social_authorization_error&quot;)); this.sessionStrategy.removeAttribute(request, &quot;social_authorization_error&quot;); } private void convertSessionAttributeToModelAttribute(String attributeName, WebRequest request, Model model) { if(this.sessionStrategy.getAttribute(request, attributeName) != null) { model.addAttribute(attributeName, Boolean.TRUE); this.sessionStrategy.removeAttribute(request, attributeName); } } private void setNoCache(NativeWebRequest request) { HttpServletResponse response = (HttpServletResponse)request.getNativeResponse(HttpServletResponse.class); if(response != null) { response.setHeader(&quot;Pragma&quot;, &quot;no-cache&quot;); response.setDateHeader(&quot;Expires&quot;, 1L); response.setHeader(&quot;Cache-Control&quot;, &quot;no-cache&quot;); response.addHeader(&quot;Cache-Control&quot;, &quot;no-store&quot;); } } }" title="" data-original-title="复制"></span> </div> </p></div> <pre><code>@Controller @RequestMapping({"/connect"}) public class ConnectController implements InitializingBean { private static final Log logger = LogFactory.getLog(ConnectController.class); private final ConnectionFactoryLocator connectionFactoryLocator; private final ConnectionRepository connectionRepository; private final MultiValueMap&lt;Class&lt;?&gt;, ConnectInterceptor&lt;?&gt;&gt; connectInterceptors = new LinkedMultiValueMap(); private final MultiValueMap&lt;Class&lt;?&gt;, DisconnectInterceptor&lt;?&gt;&gt; disconnectInterceptors = new LinkedMultiValueMap(); private ConnectSupport connectSupport; private final UrlPathHelper urlPathHelper = new UrlPathHelper(); private String viewPath = "connect/"; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); private String applicationUrl = null; protected static final String DUPLICATE_CONNECTION_ATTRIBUTE = "social_addConnection_duplicate"; protected static final String PROVIDER_ERROR_ATTRIBUTE = "social_provider_error"; protected static final String AUTHORIZATION_ERROR_ATTRIBUTE = "social_authorization_error"; @Inject public ConnectController(ConnectionFactoryLocator connectionFactoryLocator, ConnectionRepository connectionRepository) { this.connectionFactoryLocator = connectionFactoryLocator; this.connectionRepository = connectionRepository; } /** @deprecated */ @Deprecated public void setInterceptors(List&lt;ConnectInterceptor&lt;?&gt;&gt; interceptors) { this.setConnectInterceptors(interceptors); } public void setConnectInterceptors(List&lt;ConnectInterceptor&lt;?&gt;&gt; interceptors) { Iterator var2 = interceptors.iterator(); while(var2.hasNext()) { ConnectInterceptor&lt;?&gt; interceptor = (ConnectInterceptor)var2.next(); this.addInterceptor(interceptor); } } public void setDisconnectInterceptors(List&lt;DisconnectInterceptor&lt;?&gt;&gt; interceptors) { Iterator var2 = interceptors.iterator(); while(var2.hasNext()) { DisconnectInterceptor&lt;?&gt; interceptor = (DisconnectInterceptor)var2.next(); this.addDisconnectInterceptor(interceptor); } } public void setApplicationUrl(String applicationUrl) { this.applicationUrl = applicationUrl; } public void setViewPath(String viewPath) { this.viewPath = viewPath; } public void setSessionStrategy(SessionStrategy sessionStrategy) { this.sessionStrategy = sessionStrategy; } public void addInterceptor(ConnectInterceptor&lt;?&gt; interceptor) { Class&lt;?&gt; serviceApiType = GenericTypeResolver.resolveTypeArgument(interceptor.getClass(), ConnectInterceptor.class); this.connectInterceptors.add(serviceApiType, interceptor); } public void addDisconnectInterceptor(DisconnectInterceptor&lt;?&gt; interceptor) { Class&lt;?&gt; serviceApiType = GenericTypeResolver.resolveTypeArgument(interceptor.getClass(), DisconnectInterceptor.class); this.disconnectInterceptors.add(serviceApiType, interceptor); } @RequestMapping( method = {RequestMethod.GET} ) public String connectionStatus(NativeWebRequest request, Model model) { this.setNoCache(request); this.processFlash(request, model); Map&lt;String, List&lt;Connection&lt;?&gt;&gt;&gt; connections = this.connectionRepository.findAllConnections(); model.addAttribute("providerIds", this.connectionFactoryLocator.registeredProviderIds()); model.addAttribute("connectionMap", connections); return this.connectView(); } @RequestMapping( value = {"/{providerId}"}, method = {RequestMethod.GET} ) public String connectionStatus(@PathVariable String providerId, NativeWebRequest request, Model model) { this.setNoCache(request); this.processFlash(request, model); List&lt;Connection&lt;?&gt;&gt; connections = this.connectionRepository.findConnections(providerId); this.setNoCache(request); if(connections.isEmpty()) { return this.connectView(providerId); } else { model.addAttribute("connections", connections); return this.connectedView(providerId); } } @RequestMapping( value = {"/{providerId}"}, method = {RequestMethod.POST} ) public RedirectView connect(@PathVariable String providerId, NativeWebRequest request) { ConnectionFactory&lt;?&gt; connectionFactory = this.connectionFactoryLocator.getConnectionFactory(providerId); MultiValueMap&lt;String, String&gt; parameters = new LinkedMultiValueMap(); this.preConnect(connectionFactory, parameters, request); try { return new RedirectView(this.connectSupport.buildOAuthUrl(connectionFactory, request, parameters)); } catch (Exception var6) { this.sessionStrategy.setAttribute(request, "social_provider_error", var6); return this.connectionStatusRedirect(providerId, request); } } @RequestMapping( value = {"/{providerId}"}, method = {RequestMethod.GET}, params = {"oauth_token"} ) public RedirectView oauth1Callback(@PathVariable String providerId, NativeWebRequest request) { try { OAuth1ConnectionFactory&lt;?&gt; connectionFactory = (OAuth1ConnectionFactory)this.connectionFactoryLocator.getConnectionFactory(providerId); Connection&lt;?&gt; connection = this.connectSupport.completeConnection(connectionFactory, request); this.addConnection(connection, connectionFactory, request); } catch (Exception var5) { this.sessionStrategy.setAttribute(request, "social_provider_error", var5); logger.warn("Exception while handling OAuth1 callback (" + var5.getMessage() + "). Redirecting to " + providerId + " connection status page."); } return this.connectionStatusRedirect(providerId, request); } @RequestMapping( value = {"/{providerId}"}, method = {RequestMethod.GET}, params = {"code"} ) public RedirectView oauth2Callback(@PathVariable String providerId, NativeWebRequest request) { try { OAuth2ConnectionFactory&lt;?&gt; connectionFactory = (OAuth2ConnectionFactory)this.connectionFactoryLocator.getConnectionFactory(providerId); Connection&lt;?&gt; connection = this.connectSupport.completeConnection(connectionFactory, request); this.addConnection(connection, connectionFactory, request); } catch (Exception var5) { this.sessionStrategy.setAttribute(request, "social_provider_error", var5); logger.warn("Exception while handling OAuth2 callback (" + var5.getMessage() + "). Redirecting to " + providerId + " connection status page."); } return this.connectionStatusRedirect(providerId, request); } @RequestMapping( value = {"/{providerId}"}, method = {RequestMethod.GET}, params = {"error"} ) public RedirectView oauth2ErrorCallback(@PathVariable String providerId, @RequestParam("error") String error, @RequestParam(value = "error_description",required = false) String errorDescription, @RequestParam(value = "error_uri",required = false) String errorUri, NativeWebRequest request) { Map&lt;String, String&gt; errorMap = new HashMap(); errorMap.put("error", error); if(errorDescription != null) { errorMap.put("errorDescription", errorDescription); } if(errorUri != null) { errorMap.put("errorUri", errorUri); } this.sessionStrategy.setAttribute(request, "social_authorization_error", errorMap); return this.connectionStatusRedirect(providerId, request); } @RequestMapping( value = {"/{providerId}"}, method = {RequestMethod.DELETE} ) public RedirectView removeConnections(@PathVariable String providerId, NativeWebRequest request) { ConnectionFactory&lt;?&gt; connectionFactory = this.connectionFactoryLocator.getConnectionFactory(providerId); this.preDisconnect(connectionFactory, request); this.connectionRepository.removeConnections(providerId); this.postDisconnect(connectionFactory, request); return this.connectionStatusRedirect(providerId, request); } @RequestMapping( value = {"/{providerId}/{providerUserId}"}, method = {RequestMethod.DELETE} ) public RedirectView removeConnection(@PathVariable String providerId, @PathVariable String providerUserId, NativeWebRequest request) { ConnectionFactory&lt;?&gt; connectionFactory = this.connectionFactoryLocator.getConnectionFactory(providerId); this.preDisconnect(connectionFactory, request); this.connectionRepository.removeConnection(new ConnectionKey(providerId, providerUserId)); this.postDisconnect(connectionFactory, request); return this.connectionStatusRedirect(providerId, request); } protected String connectView() { return this.getViewPath() + "status"; } protected String connectView(String providerId) { return this.getViewPath() + providerId + "Connect"; } protected String connectedView(String providerId) { return this.getViewPath() + providerId + "Connected"; } protected RedirectView connectionStatusRedirect(String providerId, NativeWebRequest request) { HttpServletRequest servletRequest = (HttpServletRequest)request.getNativeRequest(HttpServletRequest.class); String path = "/connect/" + providerId + this.getPathExtension(servletRequest); if(this.prependServletPath(servletRequest)) { path = servletRequest.getServletPath() + path; } return new RedirectView(path, true); } public void afterPropertiesSet() throws Exception { this.connectSupport = new ConnectSupport(this.sessionStrategy); if(this.applicationUrl != null) { this.connectSupport.setApplicationUrl(this.applicationUrl); } } private boolean prependServletPath(HttpServletRequest request) { return !this.urlPathHelper.getPathWithinServletMapping(request).equals(""); } private String getPathExtension(HttpServletRequest request) { String fileName = this.extractFullFilenameFromUrlPath(request.getRequestURI()); String extension = StringUtils.getFilenameExtension(fileName); return extension != null?"." + extension:""; } private String extractFullFilenameFromUrlPath(String urlPath) { int end = urlPath.indexOf(63); if(end == -1) { end = urlPath.indexOf(35); if(end == -1) { end = urlPath.length(); } } int begin = urlPath.lastIndexOf(47, end) + 1; int paramIndex = urlPath.indexOf(59, begin); end = paramIndex != -1 &amp;&amp; paramIndex &lt; end?paramIndex:end; return urlPath.substring(begin, end); } private String getViewPath() { return this.viewPath; } private void addConnection(Connection&lt;?&gt; connection, ConnectionFactory&lt;?&gt; connectionFactory, WebRequest request) { try { this.connectionRepository.addConnection(connection); this.postConnect(connectionFactory, connection, request); } catch (DuplicateConnectionException var5) { this.sessionStrategy.setAttribute(request, "social_addConnection_duplicate", var5); } } private void preConnect(ConnectionFactory&lt;?&gt; connectionFactory, MultiValueMap&lt;String, String&gt; parameters, WebRequest request) { Iterator var4 = this.interceptingConnectionsTo(connectionFactory).iterator(); while(var4.hasNext()) { ConnectInterceptor interceptor = (ConnectInterceptor)var4.next(); interceptor.preConnect(connectionFactory, parameters, request); } } private void postConnect(ConnectionFactory&lt;?&gt; connectionFactory, Connection&lt;?&gt; connection, WebRequest request) { Iterator var4 = this.interceptingConnectionsTo(connectionFactory).iterator(); while(var4.hasNext()) { ConnectInterceptor interceptor = (ConnectInterceptor)var4.next(); interceptor.postConnect(connection, request); } } private void preDisconnect(ConnectionFactory&lt;?&gt; connectionFactory, WebRequest request) { Iterator var3 = this.interceptingDisconnectionsTo(connectionFactory).iterator(); while(var3.hasNext()) { DisconnectInterceptor interceptor = (DisconnectInterceptor)var3.next(); interceptor.preDisconnect(connectionFactory, request); } } private void postDisconnect(ConnectionFactory&lt;?&gt; connectionFactory, WebRequest request) { Iterator var3 = this.interceptingDisconnectionsTo(connectionFactory).iterator(); while(var3.hasNext()) { DisconnectInterceptor interceptor = (DisconnectInterceptor)var3.next(); interceptor.postDisconnect(connectionFactory, request); } } private List&lt;ConnectInterceptor&lt;?&gt;&gt; interceptingConnectionsTo(ConnectionFactory&lt;?&gt; connectionFactory) { Class&lt;?&gt; serviceType = GenericTypeResolver.resolveTypeArgument(connectionFactory.getClass(), ConnectionFactory.class); List&lt;ConnectInterceptor&lt;?&gt;&gt; typedInterceptors = (List)this.connectInterceptors.get(serviceType); if(typedInterceptors == null) { typedInterceptors = Collections.emptyList(); } return typedInterceptors; } private List&lt;DisconnectInterceptor&lt;?&gt;&gt; interceptingDisconnectionsTo(ConnectionFactory&lt;?&gt; connectionFactory) { Class&lt;?&gt; serviceType = GenericTypeResolver.resolveTypeArgument(connectionFactory.getClass(), ConnectionFactory.class); List&lt;DisconnectInterceptor&lt;?&gt;&gt; typedInterceptors = (List)this.disconnectInterceptors.get(serviceType); if(typedInterceptors == null) { typedInterceptors = Collections.emptyList(); } return typedInterceptors; } private void processFlash(WebRequest request, Model model) { this.convertSessionAttributeToModelAttribute("social_addConnection_duplicate", request, model); this.convertSessionAttributeToModelAttribute("social_provider_error", request, model); model.addAttribute("social_authorization_error", this.sessionStrategy.getAttribute(request, "social_authorization_error")); this.sessionStrategy.removeAttribute(request, "social_authorization_error"); } private void convertSessionAttributeToModelAttribute(String attributeName, WebRequest request, Model model) { if(this.sessionStrategy.getAttribute(request, attributeName) != null) { model.addAttribute(attributeName, Boolean.TRUE); this.sessionStrategy.removeAttribute(request, attributeName); } } private void setNoCache(NativeWebRequest request) { HttpServletResponse response = (HttpServletResponse)request.getNativeResponse(HttpServletResponse.class); if(response != null) { response.setHeader("Pragma", "no-cache"); response.setDateHeader("Expires", 1L); response.setHeader("Cache-Control", "no-cache"); response.addHeader("Cache-Control", "no-store"); } } }</code></pre> <p>上面就是ConnectController的源码了,我们现在分析一下获取当前用户社交绑定情况的方法:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text=" @RequestMapping( method = {RequestMethod.GET} ) public String connectionStatus(NativeWebRequest request, Model model) { this.setNoCache(request); this.processFlash(request, model); Map<String, List<Connection<?>>> connections = this.connectionRepository.findAllConnections(); model.addAttribute(&quot;providerIds&quot;, this.connectionFactoryLocator.registeredProviderIds()); model.addAttribute(&quot;connectionMap&quot;, connections); return this.connectView(); } @RequestMapping( value = {&quot;/{providerId}&quot;}, method = {RequestMethod.GET} ) public String connectionStatus(@PathVariable String providerId, NativeWebRequest request, Model model) { this.setNoCache(request); this.processFlash(request, model); List<Connection<?>> connections = this.connectionRepository.findConnections(providerId); this.setNoCache(request); if(connections.isEmpty()) { return this.connectView(providerId); } else { model.addAttribute(&quot;connections&quot;, connections); return this.connectedView(providerId); } }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs kotlin"><code> <span class="hljs-meta">@RequestMapping( method = {RequestMethod.GET} )</span> <span class="hljs-keyword">public</span> String connectionStatus(NativeWebRequest request, Model model) { <span class="hljs-keyword">this</span>.setNoCache(request); <span class="hljs-keyword">this</span>.processFlash(request, model); Map&lt;String, List&lt;Connection&lt;?&gt;&gt;&gt; connections = <span class="hljs-keyword">this</span>.connectionRepository.findAllConnections(); model.addAttribute(<span class="hljs-string">"providerIds"</span>, <span class="hljs-keyword">this</span>.connectionFactoryLocator.registeredProviderIds()); model.addAttribute(<span class="hljs-string">"connectionMap"</span>, connections); <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.connectView(); } <span class="hljs-meta">@RequestMapping( value = {<span class="hljs-meta-string">"/{providerId}"</span>}, method = {RequestMethod.GET} )</span> <span class="hljs-keyword">public</span> String connectionStatus(<span class="hljs-meta">@PathVariable</span> String providerId, NativeWebRequest request, Model model) { <span class="hljs-keyword">this</span>.setNoCache(request); <span class="hljs-keyword">this</span>.processFlash(request, model); List&lt;Connection&lt;?&gt;&gt; connections = <span class="hljs-keyword">this</span>.connectionRepository.findConnections(providerId); <span class="hljs-keyword">this</span>.setNoCache(request); <span class="hljs-keyword">if</span>(connections.isEmpty()) { <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.connectView(providerId); } <span class="hljs-keyword">else</span> { model.addAttribute(<span class="hljs-string">"connections"</span>, connections); <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.connectedView(providerId); } }</code></pre> <p>对了,就是这两个方法,前面第一个方法请求的地址是:/connect(需要用户登录) 这个地址是获取当前用户所有社交账号绑定情况,第二个方法请求的地址是:/connect/{providerId}(需要用户登录) 这个地址是获取某个社交账号绑定情况,如/connect/qq,所以我们要获取当前用户绑定的所有社交账号绑定情况,使用的是第一个方法,但是现在有个问题,获取完之后 它是直接跳转页面到/connect/status,当然这不是我们想要的,我们要修改这个类,比如地址换成/socialConnect,这个换成自己的就好,然后我们来改下这个方法,如下:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text=" @RequestMapping( method = {RequestMethod.GET} ) public ResponseEntity<?> connectionStatus(NativeWebRequest request, Model model) throws JsonProcessingException { this.setNoCache(request); this.processFlash(request, model); Map<String, List<Connection<?>>> connections = this.connectionRepository.findAllConnections(); model.addAttribute(&quot;providerIds&quot;, this.connectionFactoryLocator.registeredProviderIds()); model.addAttribute(&quot;connectionMap&quot;, connections); Map<String,Boolean> result = new HashMap<String, Boolean>(); for (String key : connections.keySet()){ result.put(key, org.apache.commons.collections.CollectionUtils.isNotEmpty(connections.get(key))); } return ResponseEntity.ok(objectMapper.writeValueAsString(result)); }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs kotlin"><code> <span class="hljs-meta">@RequestMapping( method = {RequestMethod.GET} )</span> <span class="hljs-keyword">public</span> ResponseEntity&lt;?&gt; connectionStatus(NativeWebRequest request, Model model) throws JsonProcessingException { <span class="hljs-keyword">this</span>.setNoCache(request); <span class="hljs-keyword">this</span>.processFlash(request, model); Map&lt;String, List&lt;Connection&lt;?&gt;&gt;&gt; connections = <span class="hljs-keyword">this</span>.connectionRepository.findAllConnections(); model.addAttribute(<span class="hljs-string">"providerIds"</span>, <span class="hljs-keyword">this</span>.connectionFactoryLocator.registeredProviderIds()); model.addAttribute(<span class="hljs-string">"connectionMap"</span>, connections); Map&lt;String,<span class="hljs-built_in">Boolean</span>&gt; result = new HashMap&lt;String, <span class="hljs-built_in">Boolean</span>&gt;(); <span class="hljs-keyword">for</span> (String key : connections.keySet()){ result.put(key, org.apache.commons.collections.CollectionUtils.isNotEmpty(connections.<span class="hljs-keyword">get</span>(key))); } <span class="hljs-keyword">return</span> ResponseEntity.ok(objectMapper.writeValueAsString(result)); }</code></pre> <p>改好的代码直接返回Json数据给前端,而不是跳转页面,完美解决了前后端分离项目问题,好了,我们使用postman发送请求测试看看:</p> <p><span class="img-wrap"><img data-src="/img/bVbhzv5?w=2260&amp;h=846" src="https://static.segmentfault.com/v-5cc2cd8e/global/img/squares.svg" alt="clipboard.png" title="clipboard.png" style="cursor: pointer;"></span></p> <p>如图所示,我们成功获取当前登录用户所有社交账号绑定情况了(为什么这里只有qq和微信?社交账号的类型是你application.proterties里面配置的)。</p> <h1 id="articleHeader3">4、绑定社交账号</h1> <p>好了,我们来看看绑定社交账号的方法:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text=" @RequestMapping( value = {&quot;/{providerId}&quot;}, method = {RequestMethod.POST} ) public RedirectView connect(@PathVariable String providerId, NativeWebRequest request) { ConnectionFactory<?> connectionFactory = this.connectionFactoryLocator.getConnectionFactory(providerId); MultiValueMap<String, String> parameters = new LinkedMultiValueMap(); this.preConnect(connectionFactory, parameters, request); try { return new RedirectView(this.connectSupport.buildOAuthUrl(connectionFactory, request, parameters)); } catch (Exception var6) { this.sessionStrategy.setAttribute(request, &quot;social_provider_error&quot;, var6); return this.connectionStatusRedirect(providerId, request); } } @RequestMapping( value = {&quot;/{providerId}&quot;}, method = {RequestMethod.GET}, params = {&quot;code&quot;} ) public RedirectView oauth2Callback(@PathVariable String providerId, NativeWebRequest request) { try { OAuth2ConnectionFactory<?> connectionFactory = (OAuth2ConnectionFactory)this.connectionFactoryLocator.getConnectionFactory(providerId); Connection<?> connection = this.connectSupport.completeConnection(connectionFactory, request); this.addConnection(connection, connectionFactory, request); } catch (Exception var5) { this.sessionStrategy.setAttribute(request, &quot;social_provider_error&quot;, var5); logger.warn(&quot;Exception while handling OAuth2 callback (&quot; + var5.getMessage() + &quot;). Redirecting to &quot; + providerId + &quot; connection status page.&quot;); } return this.connectionStatusRedirect(providerId, request); }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs kotlin"><code> <span class="hljs-meta">@RequestMapping( value = {<span class="hljs-meta-string">"/{providerId}"</span>}, method = {RequestMethod.POST} )</span> <span class="hljs-keyword">public</span> RedirectView connect(<span class="hljs-meta">@PathVariable</span> String providerId, NativeWebRequest request) { ConnectionFactory&lt;?&gt; connectionFactory = <span class="hljs-keyword">this</span>.connectionFactoryLocator.getConnectionFactory(providerId); MultiValueMap&lt;String, String&gt; parameters = new LinkedMultiValueMap(); <span class="hljs-keyword">this</span>.preConnect(connectionFactory, parameters, request); <span class="hljs-keyword">try</span> { <span class="hljs-keyword">return</span> new RedirectView(<span class="hljs-keyword">this</span>.connectSupport.buildOAuthUrl(connectionFactory, request, parameters)); } <span class="hljs-keyword">catch</span> (Exception var6) { <span class="hljs-keyword">this</span>.sessionStrategy.setAttribute(request, <span class="hljs-string">"social_provider_error"</span>, var6); <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.connectionStatusRedirect(providerId, request); } } <span class="hljs-meta">@RequestMapping( value = {<span class="hljs-meta-string">"/{providerId}"</span>}, method = {RequestMethod.GET}, params = {<span class="hljs-meta-string">"code"</span>} )</span> <span class="hljs-keyword">public</span> RedirectView oauth2Callback(<span class="hljs-meta">@PathVariable</span> String providerId, NativeWebRequest request) { <span class="hljs-keyword">try</span> { OAuth2ConnectionFactory&lt;?&gt; connectionFactory = (OAuth2ConnectionFactory)<span class="hljs-keyword">this</span>.connectionFactoryLocator.getConnectionFactory(providerId); Connection&lt;?&gt; connection = <span class="hljs-keyword">this</span>.connectSupport.completeConnection(connectionFactory, request); <span class="hljs-keyword">this</span>.addConnection(connection, connectionFactory, request); } <span class="hljs-keyword">catch</span> (Exception var5) { <span class="hljs-keyword">this</span>.sessionStrategy.setAttribute(request, <span class="hljs-string">"social_provider_error"</span>, var5); logger.warn(<span class="hljs-string">"Exception while handling OAuth2 callback ("</span> + var5.getMessage() + <span class="hljs-string">"). Redirecting to "</span> + providerId + <span class="hljs-string">" connection status page."</span>); } <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.connectionStatusRedirect(providerId, request); }</code></pre> <p>现在来分析 下这两个 方法的作用,第一个方法请求的地址是:POST /connect/{providerId}(需要登录) ,第二个方法请求地址是:GET /connect/{providerId}?code=&amp;state=(需要登录),第一个方法是获取社交授权连接地址(这个是你自己社交登录时候封装好的,这里我不打算详细讲解,后面课程再放出来吧)比如qq的授权地址:<a href="https://graph.qq.com/oauth2.0/show?which=Login&amp;display=pc&amp;client_id=&amp;response_type=code&amp;redirect_uri=&amp;state=" rel="nofollow noreferrer" target="_blank">https://graph.qq.com/oauth2.0...</a>,这样当你授权成功之后就回调到了第二个方法里面,顺便把code和state原样返回过来,这一套绑定机制都是基于session的,下面我们来分析看下他是如何实现的。</p> <p>我们以微信为例,首先我们发送一个POST请求/connect/wechat,因为你已经登录了,所以后台可以获取当前user是谁,然后就获取到请求的链接:<a href="https://open.weixin.qq.com/connect/qrconnect?client_id=&amp;response_type=code&amp;redirect_uri=&amp;state=&amp;appid=&amp;scope=snsapi_login" rel="nofollow noreferrer" target="_blank">https://open.weixin.qq.com/co...</a>,最后就是跳转到这个链接上面去。这是第一个方法的作用,接下来我们分析第二个方法。</p> <p>请求上面的链接之后就是跳转到微信扫码的页面,如下所示:</p> <p><span class="img-wrap"><img data-src="/img/bVbhAMI?w=1440&amp;h=1156" src="https://static.segmentfault.com/v-5cc2cd8e/global/img/squares.svg" alt="clipboard.png" title="clipboard.png" style="cursor: pointer;"></span></p> <p>扫完之后立马就跳到上面链接redirect_uri地址上面去,也就是现在的第二个方法上面,而且是带着state和code两个参数,这时候后台开始验证你回传过来的state值是不是匹配的,不匹配就报错并且跳转到出错页面,匹配的话就往下走,并且通过code获取SpringSecurity OAuth相关社交用户信息并保存到数据库中,这就是code和state的作用,验证和获取完之后就可以,这样你就绑定成功了,最后跳转到/connected/wechat页面了,这样就结束了绑定功能了。</p> <p>那么我们前后端分离项目要使用这套机制,我们必须改一下他的源码了。</p> <p>首先第一个方法,我们要把userId保存到以state的redis键值对中,也就是:{state:userId},然后以JSON的格式返回社交授权的链接给前台,这是第一个方法要修改的思路。</p> <p>然后第二个方法,是社交授权链接返回回来的,因为前后端分离项目session就无法使用了,所以要获取用户信息必须通过上面redis保存的{state:userId},来获取用户id。再一个我们通过code获取社交用户信息,两个数据都获取了,这个时候我们就可以安心的把社交用户信息保存到数据库中(这里的通过state从redis中获取userId,其实也是一种验证state的方式,你想想可是呢!),最后就跳转到你想要的页面就好了,下面就是修改后的代码了,可以看看:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="@RequestMapping( value = {&quot;/{providerId}&quot;}, method = {RequestMethod.POST} ) public ResponseEntity<?> connect(@PathVariable String providerId, NativeWebRequest request) { HttpServletRequest nativeRequest = request.getNativeRequest(HttpServletRequest.class); Principal user = nativeRequest.getUserPrincipal(); ConnectionFactory<?> connectionFactory = this.connectionFactoryLocator.getConnectionFactory(providerId); MultiValueMap<String, String> parameters = new LinkedMultiValueMap(); this.preConnect(connectionFactory, parameters, request); try { String social_connect_url = this.connectSupport.buildOAuthUrl(connectionFactory, request, parameters); String state = (String) this.sessionStrategy.getAttribute(request, &quot;oauth2State&quot;); this.sessionStrategy.removeAttribute(request, &quot;oauth2State&quot;); //把userId以state为key的形式保存到redis中 socialRedisHelper.saveStateUserId(state, user.getName()); //返回社交链接地址 return ResponseEntity.ok(social_connect_url); } catch (Exception var6) { this.sessionStrategy.setAttribute(request, &quot;social_provider_error&quot;, var6); logger.info(var6.getMessage()); return null; } } //辅助方法1 protected String callbackUrl(NativeWebRequest request) { if (this.callbackUrl != null) { return this.callbackUrl; } else { HttpServletRequest nativeRequest = request.getNativeRequest(HttpServletRequest.class); return this.applicationUrl != null ? this.applicationUrl + this.connectPath(nativeRequest) : nativeRequest.getRequestURL().toString(); } } //辅助方法2 private String connectPath(HttpServletRequest request) { String pathInfo = request.getPathInfo(); return request.getServletPath() + (pathInfo != null ? pathInfo : &quot;&quot;); } //回调方法 @RequestMapping( value = {&quot;/{providerId}&quot;}, method = {RequestMethod.GET}, params = {&quot;code&quot;} ) public void oauth2Callback(@PathVariable String providerId, NativeWebRequest request, HttpServletResponse response) { try { //ConnectController是先保存在session里面,然后回调从session里面取出来校验 //我现在是通过redis保存state 的 userId,这样就相当于校验了state String state = request.getParameter(&quot;state&quot;); String code = request.getParameter(&quot;code&quot;); OAuth2ConnectionFactory<?> connectionFactory = (OAuth2ConnectionFactory) this.connectionFactoryLocator.getConnectionFactory(providerId); AccessGrant accessGrant = connectionFactory.getOAuthOperations().exchangeForAccess(code, this.callbackUrl(request), null); Connection<?> connection = connectionFactory.createConnection(accessGrant); //从redis中获取userid String userId = socialRedisHelper.getStateUserId(state); //保存到数据库中 jdbcConnectionRepository.createConnectionRepository(userId).addConnection(connection); //跳转页面到前台任何你想设置的地址 response.sendRedirect(connectUrl); } catch (Exception ex) { logger.info(ex.getMessage()); } }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs kotlin"><code><span class="hljs-meta">@RequestMapping( value = {<span class="hljs-meta-string">"/{providerId}"</span>}, method = {RequestMethod.POST} )</span> <span class="hljs-keyword">public</span> ResponseEntity&lt;?&gt; connect(<span class="hljs-meta">@PathVariable</span> String providerId, NativeWebRequest request) { HttpServletRequest nativeRequest = request.getNativeRequest(HttpServletRequest.<span class="hljs-keyword">class</span>); Principal user = nativeRequest.getUserPrincipal(); ConnectionFactory&lt;?&gt; connectionFactory = <span class="hljs-keyword">this</span>.connectionFactoryLocator.getConnectionFactory(providerId); MultiValueMap&lt;String, String&gt; parameters = new LinkedMultiValueMap(); <span class="hljs-keyword">this</span>.preConnect(connectionFactory, parameters, request); <span class="hljs-keyword">try</span> { String social_connect_url = <span class="hljs-keyword">this</span>.connectSupport.buildOAuthUrl(connectionFactory, request, parameters); String state = (String) <span class="hljs-keyword">this</span>.sessionStrategy.getAttribute(request, <span class="hljs-string">"oauth2State"</span>); <span class="hljs-keyword">this</span>.sessionStrategy.removeAttribute(request, <span class="hljs-string">"oauth2State"</span>); <span class="hljs-comment">//把userId以state为key的形式保存到redis中</span> socialRedisHelper.saveStateUserId(state, user.getName()); <span class="hljs-comment">//返回社交链接地址</span> <span class="hljs-keyword">return</span> ResponseEntity.ok(social_connect_url); } <span class="hljs-keyword">catch</span> (Exception var6) { <span class="hljs-keyword">this</span>.sessionStrategy.setAttribute(request, <span class="hljs-string">"social_provider_error"</span>, var6); logger.info(var6.getMessage()); <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>; } } <span class="hljs-comment">//辅助方法1</span> <span class="hljs-keyword">protected</span> String callbackUrl(NativeWebRequest request) { <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.callbackUrl != <span class="hljs-literal">null</span>) { <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.callbackUrl; } <span class="hljs-keyword">else</span> { HttpServletRequest nativeRequest = request.getNativeRequest(HttpServletRequest.<span class="hljs-keyword">class</span>); <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.applicationUrl != <span class="hljs-literal">null</span> ? <span class="hljs-keyword">this</span>.applicationUrl + <span class="hljs-keyword">this</span>.connectPath(nativeRequest) : nativeRequest.getRequestURL().toString(); } } <span class="hljs-comment">//辅助方法2</span> <span class="hljs-keyword">private</span> String connectPath(HttpServletRequest request) { String pathInfo = request.getPathInfo(); <span class="hljs-keyword">return</span> request.getServletPath() + (pathInfo != <span class="hljs-literal">null</span> ? pathInfo : <span class="hljs-string">""</span>); } <span class="hljs-comment">//回调方法</span> <span class="hljs-meta">@RequestMapping( value = {<span class="hljs-meta-string">"/{providerId}"</span>}, method = {RequestMethod.GET}, params = {<span class="hljs-meta-string">"code"</span>} )</span> <span class="hljs-keyword">public</span> void oauth2Callback(<span class="hljs-meta">@PathVariable</span> String providerId, NativeWebRequest request, HttpServletResponse response) { <span class="hljs-keyword">try</span> { <span class="hljs-comment">//ConnectController是先保存在session里面,然后回调从session里面取出来校验</span> <span class="hljs-comment">//我现在是通过redis保存state 的 userId,这样就相当于校验了state</span> String state = request.getParameter(<span class="hljs-string">"state"</span>); String code = request.getParameter(<span class="hljs-string">"code"</span>); OAuth2ConnectionFactory&lt;?&gt; connectionFactory = (OAuth2ConnectionFactory) <span class="hljs-keyword">this</span>.connectionFactoryLocator.getConnectionFactory(providerId); AccessGrant accessGrant = connectionFactory.getOAuthOperations().exchangeForAccess(code, <span class="hljs-keyword">this</span>.callbackUrl(request), <span class="hljs-literal">null</span>); Connection&lt;?&gt; connection = connectionFactory.createConnection(accessGrant); <span class="hljs-comment">//从redis中获取userid</span> String userId = socialRedisHelper.getStateUserId(state); <span class="hljs-comment">//保存到数据库中</span> jdbcConnectionRepository.createConnectionRepository(userId).addConnection(connection); <span class="hljs-comment">//跳转页面到前台任何你想设置的地址</span> response.sendRedirect(connectUrl); } <span class="hljs-keyword">catch</span> (Exception ex) { logger.info(ex.getMessage()); } }</code></pre> <p>这样你就完成了后台绑定相关工作,那么我把前端相关代码也放出来大家看下吧:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="gotoBind(type){ let url = `${this.$url}/socialConnect/${type}`; this.$post(url) .then(res=>{ if(res.code == 0){ this.openWindow(res.data.redirect_uri) } }) }, openWindow(url){ let sf_H = 550; let sf_W = 720; var iTop = (window.screen.height-30 -sf_H)/2; //获得窗口的垂直位置; var iLeft = (window.screen.width-10 -sf_W)/2; //获得窗口的水平位置; let s = window.open(url,&quot;social_bind_form&quot;,'height='+sf_H+ ', width='+sf_W+',top='+iTop+',left='+iLeft+'toolbar=no, menubar=no, scrollbars=no, status=no, location=yes, resizable=yes'); }," title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs typescript"><code>gotoBind(<span class="hljs-keyword">type</span>){ <span class="hljs-keyword">let</span> url = <span class="hljs-string">`<span class="hljs-subst">${this.$url}</span>/socialConnect/<span class="hljs-subst">${type}</span>`</span>; <span class="hljs-keyword">this</span>.$post(url) .then(<span class="hljs-function"><span class="hljs-params">res</span>=&gt;</span>{ <span class="hljs-keyword">if</span>(res.code == <span class="hljs-number">0</span>){ <span class="hljs-keyword">this</span>.openWindow(res.data.redirect_uri) } }) }, openWindow(url){ <span class="hljs-keyword">let</span> sf_H = <span class="hljs-number">550</span>; <span class="hljs-keyword">let</span> sf_W = <span class="hljs-number">720</span>; <span class="hljs-keyword">var</span> iTop = (<span class="hljs-built_in">window</span>.screen.height<span class="hljs-number">-30</span> -sf_H)/<span class="hljs-number">2</span>; <span class="hljs-comment">//获得窗口的垂直位置; </span> <span class="hljs-keyword">var</span> iLeft = (<span class="hljs-built_in">window</span>.screen.width<span class="hljs-number">-10</span> -sf_W)/<span class="hljs-number">2</span>; <span class="hljs-comment">//获得窗口的水平位置;</span> <span class="hljs-keyword">let</span> s = <span class="hljs-built_in">window</span>.open(url,<span class="hljs-string">"social_bind_form"</span>,<span class="hljs-string">'height='</span>+sf_H+ <span class="hljs-string">', width='</span>+sf_W+<span class="hljs-string">',top='</span>+iTop+<span class="hljs-string">',left='</span>+iLeft+<span class="hljs-string">'toolbar=no, menubar=no, scrollbars=no, status=no, location=yes, resizable=yes'</span>); },</code></pre> <p>上面是获取社交绑定地址并跳转,下面是回调成功之后关闭对话框并刷新的页面代码。</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="<template> </p> <section> <!--社交绑定成功处理页面--> </section> <p> </template> <script> import {mapActions,mapState} from 'vuex' export default { data(){ return{ } }, created(){ window.close(); opener.location.reload(); }, methods:{ } } </script> " title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span> <span class="hljs-comment">&lt;!--社交绑定成功处理页面--&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"> <span class="hljs-keyword">import</span> {mapActions,mapState} <span class="hljs-keyword">from</span> <span class="hljs-string">'vuex'</span> <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> { data(){ <span class="hljs-keyword">return</span>{ } }, created(){ <span class="hljs-built_in">window</span>.close(); opener.location.reload(); }, <span class="hljs-attr">methods</span>:{ } } </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> </code></pre> <p>我们来演示一下:</p> <p><span class="img-wrap"><img data-src="/img/bVbhAMa?w=1720&amp;h=862" src="https://static.segmentfault.com/v-5cc2cd8e/global/img/squares.svg" alt="clipboard.png" title="clipboard.png" style="cursor: pointer;"></span></p> <p><span class="img-wrap"><img data-src="/img/bVbhAMI?w=1440&amp;h=1156" src="https://static.segmentfault.com/v-5cc2cd8e/global/img/squares.svg" alt="clipboard.png" title="clipboard.png" style="cursor: pointer;"></span></p> <p><span class="img-wrap"><img data-src="/img/bVbhAM4?w=1686&amp;h=762" src="https://static.segmentfault.com/v-5cc2cd8e/global/img/squares.svg" alt="clipboard.png" title="clipboard.png" style="cursor: pointer;"></span></p> <p><span class="img-wrap"><img data-src="/img/bVbhANd?w=2394&amp;h=628" src="https://static.segmentfault.com/v-5cc2cd8e/global/img/squares.svg" alt="clipboard.png" title="clipboard.png" style="cursor: pointer;"></span></p> <h1 id="articleHeader4">5、解绑社交账号</h1> <p>绑定社交账号已经成功了,现在我们来看一下如何解绑社交账号吧,我们先看下源码是如何实现的,如下</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="@RequestMapping( value = {&quot;/{providerId}&quot;}, method = {RequestMethod.DELETE} ) public RedirectView removeConnections(@PathVariable String providerId, NativeWebRequest request) { ConnectionFactory<?> connectionFactory = this.connectionFactoryLocator.getConnectionFactory(providerId); this.preDisconnect(connectionFactory, request); this.connectionRepository.removeConnections(providerId); this.postDisconnect(connectionFactory, request); return this.connectionStatusRedirect(providerId, request); } @RequestMapping( value = {&quot;/{providerId}/{providerUserId}&quot;}, method = {RequestMethod.DELETE} ) public RedirectView removeConnection(@PathVariable String providerId, @PathVariable String providerUserId, NativeWebRequest request) { ConnectionFactory<?> connectionFactory = this.connectionFactoryLocator.getConnectionFactory(providerId); this.preDisconnect(connectionFactory, request); this.connectionRepository.removeConnection(new ConnectionKey(providerId, providerUserId)); this.postDisconnect(connectionFactory, request); return this.connectionStatusRedirect(providerId, request); }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs kotlin"><code><span class="hljs-meta">@RequestMapping( value = {<span class="hljs-meta-string">"/{providerId}"</span>}, method = {RequestMethod.DELETE} )</span> <span class="hljs-keyword">public</span> RedirectView removeConnections(<span class="hljs-meta">@PathVariable</span> String providerId, NativeWebRequest request) { ConnectionFactory&lt;?&gt; connectionFactory = <span class="hljs-keyword">this</span>.connectionFactoryLocator.getConnectionFactory(providerId); <span class="hljs-keyword">this</span>.preDisconnect(connectionFactory, request); <span class="hljs-keyword">this</span>.connectionRepository.removeConnections(providerId); <span class="hljs-keyword">this</span>.postDisconnect(connectionFactory, request); <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.connectionStatusRedirect(providerId, request); } <span class="hljs-meta">@RequestMapping( value = {<span class="hljs-meta-string">"/{providerId}/{providerUserId}"</span>}, method = {RequestMethod.DELETE} )</span> <span class="hljs-keyword">public</span> RedirectView removeConnection(<span class="hljs-meta">@PathVariable</span> String providerId, <span class="hljs-meta">@PathVariable</span> String providerUserId, NativeWebRequest request) { ConnectionFactory&lt;?&gt; connectionFactory = <span class="hljs-keyword">this</span>.connectionFactoryLocator.getConnectionFactory(providerId); <span class="hljs-keyword">this</span>.preDisconnect(connectionFactory, request); <span class="hljs-keyword">this</span>.connectionRepository.removeConnection(new ConnectionKey(providerId, providerUserId)); <span class="hljs-keyword">this</span>.postDisconnect(connectionFactory, request); <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.connectionStatusRedirect(providerId, request); }</code></pre> <p>第一个方法请求地址是:Delete /connect/{providerId}(需登录),第二个方法请求地址是:Delete /connect/{providerId}/{providerUserId}(需登录),注意这里的providerUserId其实就是社交用户id,比如微信的openId,第一个方法是根据登录的userId和providerId来删除数据库中绑定的社交用户数据,第二个方法是根据登录的userId和providerId还有providerUserId来删除数据库中绑定的社交用户数据,这两个 方法都有相同的一点就是跳转到删除之后的页面,所以我们只要把跳转页面以JSON的形式返回给前端就好,下面就是修改后的代码:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text=" @RequestMapping( value = {&quot;/{providerId}&quot;}, method = {RequestMethod.DELETE} ) public ResponseEntity<?> removeConnections(@PathVariable String providerId, NativeWebRequest request) { ConnectionFactory<?> connectionFactory = this.connectionFactoryLocator.getConnectionFactory(providerId); this.preDisconnect(connectionFactory, request); this.connectionRepository.removeConnections(providerId); this.postDisconnect(connectionFactory, request); return ResponseEntity.ok(&quot;success&quot;); } @RequestMapping( value = {&quot;/{providerId}/{providerUserId}&quot;}, method = {RequestMethod.DELETE} ) public ResponseEntity<?> removeConnection(@PathVariable String providerId, @PathVariable String providerUserId, NativeWebRequest request) throws IOException { try { ConnectionFactory<?> connectionFactory = this.connectionFactoryLocator.getConnectionFactory(providerId); this.preDisconnect(connectionFactory, request); this.connectionRepository.removeConnection(new ConnectionKey(providerId, providerUserId)); this.postDisconnect(connectionFactory, request); } catch (Exception ex) { logger.info(ex.getMessage()); } return ResponseEntity.ok(&quot;success&quot;); }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs kotlin"><code> <span class="hljs-meta">@RequestMapping( value = {<span class="hljs-meta-string">"/{providerId}"</span>}, method = {RequestMethod.DELETE} )</span> <span class="hljs-keyword">public</span> ResponseEntity&lt;?&gt; removeConnections(<span class="hljs-meta">@PathVariable</span> String providerId, NativeWebRequest request) { ConnectionFactory&lt;?&gt; connectionFactory = <span class="hljs-keyword">this</span>.connectionFactoryLocator.getConnectionFactory(providerId); <span class="hljs-keyword">this</span>.preDisconnect(connectionFactory, request); <span class="hljs-keyword">this</span>.connectionRepository.removeConnections(providerId); <span class="hljs-keyword">this</span>.postDisconnect(connectionFactory, request); <span class="hljs-keyword">return</span> ResponseEntity.ok(<span class="hljs-string">"success"</span>); } <span class="hljs-meta">@RequestMapping( value = {<span class="hljs-meta-string">"/{providerId}/{providerUserId}"</span>}, method = {RequestMethod.DELETE} )</span> <span class="hljs-keyword">public</span> ResponseEntity&lt;?&gt; removeConnection(<span class="hljs-meta">@PathVariable</span> String providerId, <span class="hljs-meta">@PathVariable</span> String providerUserId, NativeWebRequest request) throws IOException { <span class="hljs-keyword">try</span> { ConnectionFactory&lt;?&gt; connectionFactory = <span class="hljs-keyword">this</span>.connectionFactoryLocator.getConnectionFactory(providerId); <span class="hljs-keyword">this</span>.preDisconnect(connectionFactory, request); <span class="hljs-keyword">this</span>.connectionRepository.removeConnection(new ConnectionKey(providerId, providerUserId)); <span class="hljs-keyword">this</span>.postDisconnect(connectionFactory, request); } <span class="hljs-keyword">catch</span> (Exception ex) { logger.info(ex.getMessage()); } <span class="hljs-keyword">return</span> ResponseEntity.ok(<span class="hljs-string">"success"</span>); }</code></pre> <p>我们再把前端代码贴出来:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="gotoUnBind(type){ let url = `${this.$url}/socialConnect/${type}`; this.$delete(url) .then(res=>{ if(res.code == 0){ this.$Message.success('解绑成功!') location.reload(); } }) }," title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs typescript"><code>gotoUnBind(<span class="hljs-keyword">type</span>){ <span class="hljs-keyword">let</span> url = <span class="hljs-string">`<span class="hljs-subst">${this.$url}</span>/socialConnect/<span class="hljs-subst">${type}</span>`</span>; <span class="hljs-keyword">this</span>.$<span class="hljs-keyword">delete</span>(url) .then(<span class="hljs-function"><span class="hljs-params">res</span>=&gt;</span>{ <span class="hljs-keyword">if</span>(res.code == <span class="hljs-number">0</span>){ <span class="hljs-keyword">this</span>.$Message.success(<span class="hljs-string">'解绑成功!'</span>) location.reload(); } }) },</code></pre> <h1 id="articleHeader5">6、总结:</h1> <p>1、只要把思路理清楚了,其实修改成自己想要的代码就不难<br />2、注意ConnectController代码是基于Session的,所以你必须要登录的情况下才能使用<br />3、redis的使用在这里发挥到了一定作用,所以说前后端分离项目离不开redis</p> <h1 id="articleHeader6">7、引用</h1> <p><a href="http://wiki.connect.qq.com/get_user_info" rel="nofollow noreferrer" target="_blank">qq互联文档</a><br /><a href="https://my.oschina.net/giegie/blog/1605932" rel="nofollow noreferrer" target="_blank">Spring Security Oauth2.0 实现短信验证码登录</a><br /><a href="http://www.dewafer.com/2016/10/01/dive-into-spring-security/" rel="nofollow noreferrer" target="_blank">深入了解 Spring Security</a><br /><a href="https://github.com/longfeizheng/logback" rel="nofollow noreferrer" target="_blank">SpringBoot+Spring Security基本配置</a><br /><a href="https://github.com/trautonen/spring-social-mongodb" rel="nofollow noreferrer" target="_blank">spring-social-mongodb</a><br /><a href="https://blog.csdn.net/u014033756/article/details/52038114" rel="nofollow noreferrer" target="_blank">微信的redirect_uri参数错误解决办法</a><br /><a href="https://www.jianshu.com/p/5b5c2131bff9" rel="nofollow noreferrer" target="_blank">网页微信第三方登录-redirect_uri参数错误</a><br /><a href="https://www.jianshu.com/p/8faaad6e9aec" rel="nofollow noreferrer" target="_blank">Java实现QQ、微信、新浪微博第三方登录</a><br /><a href="https://www.cnblogs.com/liuxianan/p/java-qq-weibo-login.html" rel="nofollow noreferrer" target="_blank">如何从零开始对接第三方登录(Java版):QQ登录和微博登录</a><br /><a href="https://www.jianshu.com/p/217abf004545" rel="nofollow noreferrer" target="_blank">QQ授权登录改</a><br /><a href="https://qtdebug.com/spring-security-11-qq-login/" rel="nofollow noreferrer" target="_blank">Spring Security QQ 登陆</a><br /><a href="https://blog.csdn.net/qq_34206863/article/details/78778058" rel="nofollow noreferrer" target="_blank">第三方APP实现QQ登陆</a><br /><a href="https://blog.csdn.net/silent_paladin/article/details/72775782" rel="nofollow noreferrer" target="_blank">2 Apache Shiro 身份认证(登录)</a><br /><a href="https://www.jianshu.com/p/51b558780098" rel="nofollow noreferrer" target="_blank">Spring Security 实战:QQ登录实现</a><br /><a href="https://blog.csdn.net/shanshan_blog/article/details/71514087" rel="nofollow noreferrer" target="_blank">基于Spring的QQ第三方登录实现</a><br /><a href="https://blog.csdn.net/dandandeshangni/article/details/79016125" rel="nofollow noreferrer" target="_blank">Spring Security源码分析三:Spring Social实现QQ社交登录</a><br /><a href="https://blog.csdn.net/u012682683/article/details/78201371?locationNum=9&amp;fps=1" rel="nofollow noreferrer" target="_blank">微信授权登录-前后端分离</a><br /><a href="http://blog.didispace.com/spring-security-oauth2-xjf-1/" rel="nofollow noreferrer" target="_blank">从零开始的Spring Security Oauth2(一)</a><br /><a href="https://spring.io/guides/tutorials/spring-boot-oauth2/" rel="nofollow noreferrer" target="_blank">Spring Boot and OAuth2</a><br /><a href="https://juejin.im/post/5a3cbce05188252582279467" rel="nofollow noreferrer" target="_blank">Spring security OAuth2 深入解析</a><br /><a href="http://www.leftso.com/blog/139.html" rel="nofollow noreferrer" target="_blank">spring boot 入门之security oauth2 jwt完美整合例子-java编程</a><br /><a href="https://github.com/jojozhai/security" rel="nofollow noreferrer" target="_blank">jojozhai/security</a><br /><a href="https://blog.csdn.net/shannon8/article/details/72896408" rel="nofollow noreferrer" target="_blank">window.open打开的窗口关闭后刷新父页面的子页面</a><br /><a href="https://www.cnblogs.com/softidea/p/7153047.html" rel="nofollow noreferrer" target="_blank">Spring Security 实战:QQ登录实现</a><a href="https://jwt.io" rel="nofollow noreferrer" target="_blank">jwt</a></p> <p></code></p>
脚本宝典为你提供优质服务
脚本宝典 » 前后端分离项目 — SpringSocial 绑定与解绑社交账号如微信、QQ

发表评论

提供最优质的资源集合

立即查看 了解详情