转载

22.SpringSecurity-处理注册逻辑

前言

上一节中我们已经处理完了

22.SpringSecurity-处理注册逻辑

上一节中我们已经走完了oauth流程,拿到了服务提供商的信息,但是在交给OAuthenticationProvider处理时候出了问题,在SocialAuthenticationProvider处他把我们导向了signup的路径,下面我们看下为什么出现在这个结果。

SocialAuthenticationProvider类下的authenticate方法:

public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        //1.判断是否是我们之前通过Connection组装的SocialAuthenticationToken授权对象  
        Assert.isInstanceOf(SocialAuthenticationToken.class, authentication, "unsupported authentication type");
        Assert.isTrue(!authentication.isAuthenticated(), "already authenticated");
        SocialAuthenticationToken authToken = (SocialAuthenticationToken)authentication;
        String providerId = authToken.getProviderId();
        
        //2.connection里面封装了:qq的providerId(qq应用id)和providerUserId(qq应用上的用户id)
        Connection<?> connection = authToken.getConnection();
        
        //3.根据connection里的roviderId和providerUserId去用户关联表查询对应业务系统的userId  
        String userId = this.toUserId(connection);
        
        //4.第一次获取不到,会跑一个异常,异常最后会被:Social AuthenticationFilter获取到  
        if (userId == null) {
            throw new BadCredentialsException("Unknown access token");
        } else {
            UserDetails userDetails = this.userDetailsService.loadUserByUserId(userId);
            if (userDetails == null) {
                throw new UsernameNotFoundException("Unknown connected account id");
            } else {
                return new SocialAuthenticationToken(connection, userDetails, authToken.getProviderAccountData(), this.getAuthorities(providerId, userDetails));
            }
        }
    }
    
protected String toUserId(Connection<?> connection) {
    List<String> userIds = this.usersConnectionRepository.findUserIdsWithConnection(connection);
    return userIds.size() == 1 ? (String)userIds.iterator().next() : null;
}

throw new BadCredentialsException("Unknown access token")抛去异常会被SocialAuthenticationFilter捕获到:如果你配置了一个signupUrl,那么就会跳转到signupUrl地址。

22.SpringSecurity-处理注册逻辑

默认的signupUrl是"/signup";

22.SpringSecurity-处理注册逻辑

因为我们没有对:signup做授权,所以会被拦截下来,然后跳转到需要授权的请求路径上:/authentication/require

内容

我们该怎样解决这个问题呢?其实很简单:我们自己写一个注册页,然后把signupUrl配置成我们自己写的注册页,最后再配置下授权,让那个注册页不经过身份认证就可以访问。

1.注册页

1.1 spring-security-web配置提示

1.1.1 配置页面

针对于不同的平台注册页信息不同,所以我们需要自定义注册页信息,这个信息是写在S配置文件中:具体注册页是在spring-security-demo里面自己写的。我们只会在spring-security-web时候做一个提示。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body>
    <h2>标准注册页面</h2>
    <h3>这是系统注册页面,请配置yxm.security.browser.signUpUrl属性来设置自己的注册页</h3>
</body>
</html>

1.1.2.BrowserProperties--添加注册页

22.SpringSecurity-处理注册逻辑

有了上面配置项之后我们就可以在spring-security-demo里面去配置:

22.SpringSecurity-处理注册逻辑

1.2 spring-security-demo里面具体些配置信息

在spring-security-demo里面,我们配置个性化的登录页:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<h2>Demo注册页</h2>
<form action="/user/regist" method="post">
    <table>
        <tr>
            <td>用户名:</td>
            <td><input type="text" name="username"></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="password" name="password"></td>
        </tr>
        <tr>
            <td colspan="2">
                <!--不存在的用户:我们是采用注册:regist-->
                <button type="submit" name="type" value="regist">注册</button>
                <!--已经存在的用户,我们是去做一个绑定-->
                <button type="submit" name="type" value="binding">绑定</button>
            </td>
        </tr>
    </table>
</form>
</body>
</html>

1.3 spring-security-demo注册用户后端

我们在UserController里面注册用户

22.SpringSecurity-处理注册逻辑

1.4 spring-security-web配置注册用户请求授权

我们授权signUp的请求,让系统不去拦截。

22.SpringSecurity-处理注册逻辑

1.5 spring-security-core配置SocialConfig

让过滤器知道,找不到用户的时候,跳到我们指定的地址上去:

22.SpringSecurity-处理注册逻辑

以上我们测试: 1.点击qq登录会转到需要在第三方授权的页面,然后授权之后会返回到第三方应用系统自带的登录页

22.SpringSecurity-处理注册逻辑

2.现在有两个问题

  1. 第一针对于上面的登录页面;我们希望能将用户的QQ信息显示在登陆页上(比如:头像、账号等提示信息),这样界面更加友好.因为我们要考虑如何拿到用户登录的社交信息。
  2. 第二是我们点了注册后会跳转到我demo项目的注册方法register中进行处理,不管注册还是绑定,最终我们能获取到一个用户的唯一标识:UserId,我们如何把UserId传回给Spring Social;让Spring Social把用户id和之前拿到的社交信息一起一起存数据库中的yxm_UserConnect表中.

为了处理这两个问题,Spring提供了一个工具类ProviderSignInUtils.我们在SocialConfig中对其进行配置,其实他就解决了2个问题:

  1. 在注册过程中如何拿到Spring Social信息
  2. 注册完成之后,如何把业务系统的数据绑定到:Spring Social

2.1 spring Social信息获取

22.SpringSecurity-处理注册逻辑

然后我们在WebSecurityController里面提供一个使用ProviderSignInUtils返回SocialUserInfo的方法

有了这些SocialUserInfo前台就能返回一个友好的用户提示来。

22.SpringSecurity-处理注册逻辑

public class SocialUserInfo {
    private String providerId;
    private String providerUserId;
    private String nickname;
    private String headimg;
    //getter setter方法
}

我们从session里面获取到了对应的值,那么我们是什么时候放入到session里面的呢?

22.SpringSecurity-处理注册逻辑

我们先把SocialUserInfo部门相关信息存储在session中,然后跳转到signUp,然后进入/social/user类中来设置用户信息。

2.2 配置UserController

我们将信息传给user后,到数据库中注册到User表,再用providerSignUitls到数据库中注册到Userconnetion表,因为需要从session中取值,所以还需呀传一个request.这里为了方便没写具体的注册逻辑.

22.SpringSecurity-处理注册逻辑

这个路径按理说是demo项目里的路径,只有demo项目知道它要到这里面注册,在后面我们在授权的时候将只有用户知道的路径剥离,让用户自己去写.

输入QQ凭证,进入注册页,进行注册,userId为xxx,再次输入QQ凭证,可以直接进入系统,打印出的凭证显示userId为xxx.

22.SpringSecurity-处理注册逻辑

3.现在有两个问题

22.SpringSecurity-处理注册逻辑

22.SpringSecurity-处理注册逻辑

22.SpringSecurity-处理注册逻辑

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