继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

spring-security-oauth2

慕虎7371278
关注TA
已关注
手记 1259
粉丝 203
获赞 873

发送验证码的Controller

首先我们需要创建一个发送验证码的 Controller, 至于如何实现,这里就不多说了,大家都会的,本篇重点说明验证部分.
【注意】在认证服务器上增加自己的 Controller, 默认情况下访问是返回403,有两种办法解决:

  1. 把认证服务器也配制为资源服务器,既: 它既是认证服务器,也是资源服务器.并配制新增的Controller为任何人都能访问

  2. 关闭认证服务器的 csrf.

由于我在认证服务器上增加的都是认证相关的功能,任何人都能访问,不需要资源保护,所以我选择了第二种方法.

关闭认证服务器的 csrf

在配制认证服务器的时候,我们创建过一个org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter 的子类用于安全配制. 如果你当时没有配制,增加一个就行.

import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.security.crypto.password.PasswordEncoder;@Configuration@EnableWebSecuritypublic class SecurityConfiguration extends WebSecurityConfigurerAdapter {    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();  // 关闭 csrf
    }
}

增加短信验证码的 TokenGranter

参考 org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter 的代码

import org.apache.commons.lang3.StringUtils;import org.springframework.core.env.Environment;import org.springframework.security.authentication.AbstractAuthenticationToken;import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;import org.springframework.security.core.Authentication;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UserDetailsChecker;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;import org.springframework.security.oauth2.provider.ClientDetails;import org.springframework.security.oauth2.provider.ClientDetailsService;import org.springframework.security.oauth2.provider.OAuth2Authentication;import org.springframework.security.oauth2.provider.OAuth2Request;import org.springframework.security.oauth2.provider.OAuth2RequestFactory;import org.springframework.security.oauth2.provider.TokenRequest;import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;

public class SMSCodeTokenGranter extends AbstractTokenGranter {

    private static final String GRANT_TYPE = "sms_code";

    public SMSCodeLoginTokenGranter(AuthorizationServerTokenServices tokenServices,
        ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {    super(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
    }

    @Override
    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client,
        TokenRequest tokenRequest) {    
    Map<String, String> parameters = new LinkedHashMap<String, String>(tokenRequest.getRequestParameters());    String userMobileNo = parameters.get("username");  //客户端提交的用户名
    String smscode = parameters.get("smscode");  //客户端提交的验证码
    
    // 从库里查用户
    UserDetails user = 从库里查找用户的代码略;    if(user == null) {        throw new InvalidGrantException("用户不存在");
    }
    
    验证用户状态(是否警用等),代码略    // 验证验证码
    String smsCodeCached = 获取服务中保存的用户验证码,代码略.一般我们是在生成好后放到缓存中    if(StringUtils.isBlank(smsCodeCached)) {        throw new InvalidGrantException("用户没有发送验证码");
    }    if(!smscode.equals(smsCodeCached)) {        throw new InvalidGrantException("验证码不正确");
    }else {
        验证通过后从缓存中移除验证码,代码略
    }

    
    Authentication userAuth = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());    // 关于user.getAuthorities(): 我们的自定义用户实体是实现了 
    // org.springframework.security.core.userdetails.UserDetails 接口的, 所以有 user.getAuthorities()
    // 当然该参数传null也行
    ((AbstractAuthenticationToken) userAuth).setDetails(parameters);
    
    OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);      
    return new OAuth2Authentication(storedOAuth2Request, userAuth);
    }

}

把 SMSCodeTokenGranter  加入到 CompositeTokenGranter 需要的 List<TokenGranter> 中

在上一篇中我们修改了 OAuth2AuthorizationServerConfig类,现在继续修改:
我们在 getDefaultTokenGranters 方法中加入:

tokenGranters.add(new SMSCodeLoginTokenGranter(tokenServices, clientDetails, requestFactory, userDetailsService));

getDefaultTokenGranters 的完整代码:

private List<TokenGranter> getDefaultTokenGranters() {
    ClientDetailsService clientDetails = clientDetailsService();
    AuthorizationServerTokenServices tokenServices = tokenServices();
    AuthorizationCodeServices authorizationCodeServices = authorizationCodeServices();
    OAuth2RequestFactory requestFactory = requestFactory();    List<TokenGranter> tokenGranters = new ArrayList<TokenGranter>();
    tokenGranters.add(new AuthorizationCodeTokenGranter(tokenServices,
        authorizationCodeServices, clientDetails, requestFactory));
    tokenGranters.add(new RefreshTokenGranter(tokenServices, clientDetails, requestFactory));
    ImplicitTokenGranter implicit = new ImplicitTokenGranter(tokenServices, clientDetails,
        requestFactory);
    tokenGranters.add(implicit);
    tokenGranters.add(        new ClientCredentialsTokenGranter(tokenServices, clientDetails, requestFactory));    if (authenticationManager != null) {
        tokenGranters.add(new ResourceOwnerPasswordTokenGranter(authenticationManager,
            tokenServices, clientDetails, requestFactory));
    }
    
    tokenGranters.add(new SMSCodeLoginTokenGranter(tokenServices, clientDetails, requestFactory, userDetailsService));    return tokenGranters;
    }

其他代码不用修改

如何使用我们新增的短信验证码方式?

我们调用  /oauth/token 进行认证的时候,有一个 grant_type 参数,我们把它的值改为 sms_code
password 参数可以不要了,新增一个 smscode 参数
当然,上面的 "sms_code" 和 "smscode" 也是可以修改的:
"sms_code" 对应 SMSCodeTokenGranter  中的静态常量 GRANT_TYPE
"smscode" 对应 SMSCodeTokenGranter.getOAuth2Authentication 方法中的 parameters.get("smscode");



作者:邪影oO
链接:https://www.jianshu.com/p/b7a474446a4c


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP