当前位置: 移动技术网 > IT编程>开发语言>Java > SpringBoot + SpringSecurity 短信验证码登录功能实现

SpringBoot + SpringSecurity 短信验证码登录功能实现

2019年07月19日  | 移动技术网IT编程  | 我要评论

实现原理

在之前的文章中,我们介绍了普通的帐号密码登录的方式: springboot + spring security 基本使用及个性化登录配置。 但是现在还有一种常见的方式,就是直接通过手机短信验证码登录,这里就需要自己来做一些额外的工作了。

springsecurity认证流程详解有一定了解的都知道,在帐号密码认证的过程中,涉及到了以下几个类:usernamepasswordauthenticationfilter(用于请求参数获取),usernamepasswordauthenticationtoken(表示用户登录信息),providermanager(进行认证校验),

因为是通过的短信验证码登录,所以我们需要对请求的参数,认证过程,用户登录token信息进行一定的重写。
当然验证码的过程我们应该放在最前面,如果的实现一样。这样的做法的好处是:将验证码认证该过程解耦出来,让其他接口也可以使用到。

基本实现

验证码校验

短信验证码的功能实现,其实和图形验证码的原理是一样的。只不过一个是返回给前端一个图片,一个是给用户发送短消息,这里只需要去调用一下短信服务商的接口就好了。更多的原理可以参考 springboot + springsecurity 实现图形验证码功能

authenticationtoken

在使用帐号密码登录的时候,usernamepasswordauthenticationtoken里面包含了用户的帐号,密码,以及其他的是否可用等状态信息。我们是通过手机短信来做登录,所以就没有密码了,这里我们就直接将usernamepasswordauthenticationtoken的代码copy过来,把密码相关的信息去掉就可以了

public class smscodeauthenticationtoken extends abstractauthenticationtoken {

  private static final long serialversionuid = springsecuritycoreversion.serial_version_uid;

  private final object principal;

  public smscodeauthenticationtoken(string mobile) {
    super(null);
    this.principal = mobile;
    setauthenticated(false);
  }

  public smscodeauthenticationtoken(object principal,
                   collection<? extends grantedauthority> authorities) {
    super(authorities);
    this.principal = principal;
    super.setauthenticated(true); // must use super, as we override
  }

  public object getcredentials() {
    return null;
  }

  public object getprincipal() {
    return this.principal;
  }

  public void setauthenticated(boolean isauthenticated) throws illegalargumentexception {
    if (isauthenticated) {
      throw new illegalargumentexception(
          "cannot set this token to trusted - use constructor which takes a grantedauthority list instead");
    }
    super.setauthenticated(false);
  }

  @override
  public void erasecredentials() {
    super.erasecredentials();
  }
}

authenticationfilter

在帐户密码登录的流程中,默认使用的是usernamepasswordauthenticationfilter,它的作用是从请求中获取帐户、密码,请求方式校验,生成authenticationtoken。这里我们的参数是有一定改变的,所以还是老方法,copy过来进行简单的修改

public class smscodeauthenticationfilter extends abstractauthenticationprocessingfilter {
  // 请求参数key
  private string mobileparameter = securityconstants.default_parameter_name_mobile;
  // 是否只支持post
  private boolean postonly = true;

  public smscodeauthenticationfilter() {
    // 请求接口的url
    super(new antpathrequestmatcher(securityconstants.default_login_processing_url_mobile, "post"));
  }

  public authentication attemptauthentication(httpservletrequest request, httpservletresponse response)
      throws authenticationexception {
    if (postonly && !request.getmethod().equals("post")) {
      throw new authenticationserviceexception("authentication method not supported: " + request.getmethod());
    }
    // 根据请求参数名,获取请求value
    string mobile = obtainmobile(request);
    if (mobile == null) {
      mobile = "";
    }
    mobile = mobile.trim();

    // 生成对应的authenticationtoken
    smscodeauthenticationtoken authrequest = new smscodeauthenticationtoken(mobile);

    setdetails(request, authrequest);

    return this.getauthenticationmanager().authenticate(authrequest);
  }

  /**
   * 获取手机号
   */
  protected string obtainmobile(httpservletrequest request) {
    return request.getparameter(mobileparameter);
  }
  // 省略不相关代码
}

provider

在帐号密码登录的过程中,密码的正确性以及帐号是否可用是通过daoauthenticationprovider来校验的。我们也应该自己实现一个provier

public class smscodeauthenticationprovider implements authenticationprovider {

  private userdetailsservice userdetailsservice;

  /**
   * 身份逻辑验证
   * @param authentication
   * @return
   * @throws authenticationexception
   */
  @override
  public authentication authenticate(authentication authentication) throws authenticationexception {

    smscodeauthenticationtoken authenticationtoken = (smscodeauthenticationtoken) authentication;

    userdetails user = userdetailsservice.loaduserbyusername((string) authenticationtoken.getprincipal());

    if (user == null) {
      throw new internalauthenticationserviceexception("无法获取用户信息");
    }

    smscodeauthenticationtoken authenticationresult = new smscodeauthenticationtoken(user, user.getauthorities());

    authenticationresult.setdetails(authenticationtoken.getdetails());

    return authenticationresult;
  }

  @override
  public boolean supports(class<?> authentication) {
    return smscodeauthenticationtoken.class.isassignablefrom(authentication);
  }

  public userdetailsservice getuserdetailsservice() {
    return userdetailsservice;
  }

  public void setuserdetailsservice(userdetailsservice userdetailsservice) {
    this.userdetailsservice = userdetailsservice;
  }
}

配置

主要的认证流程就是通过以上四个过程实现的, 这里我们再降它们配置一下就可以了

@component
public class smscodeauthenticationsecurityconfig extends securityconfigureradapter<defaultsecurityfilterchain, httpsecurity> {

  @autowired
  private authenticationsuccesshandler myauthenticationsuccesshandler;

  @autowired
  private authenticationfailurehandler myauthenticationfailurehandler;

  @autowired
  private userdetailsservice userdetailsservice;

  @override
  public void configure(httpsecurity http) throws exception {

    smscodeauthenticationfilter smscodeauthenticationfilter = new smscodeauthenticationfilter();
    smscodeauthenticationfilter.setauthenticationmanager(http.getsharedobject(authenticationmanager.class));
    smscodeauthenticationfilter.setauthenticationsuccesshandler(myauthenticationsuccesshandler);
    smscodeauthenticationfilter.setauthenticationfailurehandler(myauthenticationfailurehandler);

    smscodeauthenticationprovider smscodeauthenticationprovider = new smscodeauthenticationprovider();
    smscodeauthenticationprovider.setuserdetailsservice(userdetailsservice);

    http.authenticationprovider(smscodeauthenticationprovider)
        .addfilterafter(smscodeauthenticationfilter, usernamepasswordauthenticationfilter.class);

  }
}
 
// browersecurityconfig.java
@override
protected void configure(httpsecurity http) throws exception {
  http.apply(smscodeauthenticationsecurityconfig);
}

代码下载

spring-security

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网