转载

21.SpringSecurity-开发QQ登录(下)

https://blog.csdn.net/q610376681/article/details/86546935

1.redirect url is illegal

1.1 域名问题

我们访问时候出现如下错误:

21.SpringSecurity-开发QQ登录(下)

在之前的第三步,返回Client并携带授权码,返回的Client的地址就是就是现在的redirect地址,地址是如何确定的呢,就是我们在QQ互联上注册时要填写一个回调域,回调域只要配置一个域名就可以了.

21.SpringSecurity-开发QQ登录(下)

我们现在的回调域是下图,我们现在的回调域是有问题的,回调域只要填写域名就可以了,比如365.com,我们传过去的uri是下图,我们访问的地址与服务器跳转回来的地址都应该是登陆时填写的地址.即/auth/qq,那我们现在的uri是localhost,实际回调的是365.com,我们现在要做的就是让redirect参数和rederect地址保持一致.

现在我们将365.com映射到了本机地址,但是它访问的是80端口,因为安全的原因,80端口被禁用了,所有访问80端口的都会跳到9090端口,所以在application.properties中做如下配置.

结果就是当访问www.pinzhi365.com,就会访问本机的localhost:9090端口.

21.SpringSecurity-开发QQ登录(下)

#### 1.2 地址问题

现在我们的地址是/auth/qq,如何改变呢?

我们之前配过SpringSocialConfigure,并将它注了进去

我们之前在spring-security-core里面配置过过SpringSocialConfigure

21.SpringSecurity-开发QQ登录(下)

在spring-security-web里面注入了:

21.SpringSecurity-开发QQ登录(下)

我们查看SpringSocialConfigurer代码,里面有一个configure方法,此方法是new了一个SocialAuthenticationFilter,然后将其加入到过滤器前的AbstractPreAuthenticatedProcessingFilter前面,加入到之前执行了postProcess方法:

protected <T> T postProcess(T object) {
    return this.objectPostProcessor.postProcess(object);
}

21.SpringSecurity-开发QQ登录(下)

21.SpringSecurity-开发QQ登录(下)

addFilterBefore((Filter)this.postProcess(filter), AbstractPreAuthenticatedProcessingFilter.class);

我们现在要做的是继承SpringSocialConfigurer,把方法:postProcess覆盖掉:

public class MySpringSocialConfigurer extends SpringSocialConfigurer {

    private String filterProcessesUrl;

    public MySpringSocialConfigurer(String filterProcessesUrl){
        this.filterProcessesUrl = filterProcessesUrl;
    }

    @Override
    protected <T> T postProcess(T object) {
        /**
         * 1.我们覆盖SpringSocialConfigurer的postProcess
         * 2.里面的object就是我们之前:SocialAuthenticationFilter
         */
        //1.获取父类处理的结果
        SocialAuthenticationFilter filter = (SocialAuthenticationFilter)super.postProcess(object);
        //2.设置FilterProcessesUrl,由于我们每个应用传递的FilterProcessesUrl可能是不一样的,所以我们将其作为可配置的
        filter.setFilterProcessesUrl(filterProcessesUrl);
        return super.postProcess(object);
    }
}

然后我们在SocialConfig里面配置成我们自己定义的类

21.SpringSecurity-开发QQ登录(下)

SecurityProperties属性为:

public class SocialProperties {
   /**
    * SocialAuthenticationFilter的默认过滤器url是:/auth
    */
   private String  filterProcessesUrl="/auth";
   private QQProperties qq = new QQProperties();
  //setter getter
}

然后我们第三方应用配置文件去配置application.yml:

yxm:
  security:
     social:
       filterProcessesUrl: /qqLogin
       qq:
         app-id: xxx
         app-secret: xxxx
         providerId: callback.do

然后我们去前端配置(现在我们更改了配置filterProcessUrl为申请应用的后缀:/qqLogin):

<h3>社交登录</h3>
<a href="/qqLogin/callback.do">QQ登录</a>

所以以上地址也是第三步骤中引导客户访问的跳转地址:/qqLogin/callback.do 和qq互联的配置地址是一致的。 用户授权完跳回来也是在这个地址上。

21.SpringSecurity-开发QQ登录(下)

跳进去之后:

21.SpringSecurity-开发QQ登录(下)

提示没有认证:看下请求的日志:

21.SpringSecurity-开发QQ登录(下)

因为默认情况下,我们是没有配置:sigin拦截请求的

我们先看下spring social执行第三方登录时候的代码:主要接口、实现类、以及调用顺序图:

21.SpringSecurity-开发QQ登录(下)

  1. 与验证码、短信拦截登录请求是一样的。
  2. 过滤器去拦截请求,将信息包装到Authentication实现中,然后传递给AuthenticationManager,Manager根据其管理的实现不同挑一个provider来处理传进来的校验信息,在处理的过程中其会调用我们书写的SocialUserDetailsService接口的实现来获取用户的信息,将用户的信息封装到SocialUserDetails接口的实现中,进行检查和校验,如果都通过了那么会把用户信息放到我们之前封装的Authentication中,然后把Authentication标记成经过认证的.
  3. 在SpringSocial提供的第三方登陆中涉及了一些特殊的东西,比如说过滤器在封装Authentication给Manager的时候,用到的一个接口叫做SocialAuthenticationService,此Service将执行整个OAuth的流程,在执行的过程中会调用我们的ConnectionFactory,ConnectionFactory会拿到ServiceProvider,ServiceProvider中有一个OAuth2Operations,它会帮助SpringSocial完成整个流程,完成流程后会拿到服务提供商的信息,服务提供商的信息会封装到Connection中,Connection会被封装到SocialAuthenticationToken,Token会被交由Manager中,然后被交由SocialAuthenticationProvider来处理此Token,provider在处理时会根据传过来的connetion里的服务提供商的信息,使用我们jdbcUsersConnectionRepository去从数据库中查询一个UserId出来,查找到UserId再调用我们的SocialUserDetialsService查出来我们的SocialUserDetails,最后再把SocialUserDetails放在SocialAuthenticationToken中,标记为已经过身份认证,放在SecurityContext里,最终放在session里.

蓝色的都是系统实现的,橘色的是我们自己写的

上面出现问题也是因为:在我们的授权蓝色模块出现问题,signin没有请求拦截到:也就是OAuth2AuthenticationService问题。我们追踪下代码:

判断有没有授权码,如果没有就抛出异常.如果有就拿授权码去换令牌.通过打断点我们发现是换令牌的过程中出现了异常.

public SocialAuthenticationToken getAuthToken(HttpServletRequest request, HttpServletResponse response) throws SocialAuthenticationRedirectException {
    String code = request.getParameter("code");
    //第3步和第4步骤都是会走此逻辑/qqLogin/callback.do;我们根据是否有授权码来判断是第3步还是第4步。  
    
    
    if (!StringUtils.hasText(code)) {//有授权码:说明是第四步:此时我们会去操作连接工厂
        OAuth2Parameters params = new OAuth2Parameters();
        params.setRedirectUri(this.buildReturnToUrl(request));
        this.setScope(request, params);
        params.add("state", this.generateState(this.connectionFactory, request));
        this.addCustomParameters(params);
        throw new SocialAuthenticationRedirectException(this.getConnectionFactory().getOAuthOperations().buildAuthenticateUrl(params));
    } else if (StringUtils.hasText(code)) {//没有授权码:说明是第3步:此时我们会调用服务提供商的getOAuthOperations()的exchangeForAccess
        try {
            String returnToUrl = this.buildReturnToUrl(request);
            AccessGrant accessGrant = this.getConnectionFactory().getOAuthOperations().exchangeForAccess(code, returnToUrl, (MultiValueMap)null);
            Connection<S> connection = this.getConnectionFactory().createConnection(accessGrant);
            return new SocialAuthenticationToken(connection, (Map)null);
        } catch (RestClientException var7) {
            this.logger.debug("failed to exchange for access", var7);
            return null;
        }
    } else {
        return null;
    }
    }
this.getConnectionFactory().getOAuthOperations().exchangeForAccess(code, returnToUrl, (MultiValueMap)null)

21.SpringSecurity-开发QQ登录(下)

上面会通过OAuth2Template调用:

21.SpringSecurity-开发QQ登录(下)

原文  https://segmentfault.com/a/1190000022057030
正文到此结束
Loading...