序言

在测试的时候,当其他人批改了某一个用户明码,那么想要登陆该用户进行测试则须要重置数据库,那么此时须要减少一种非凡的登陆形式,不依附账户:Google Authenticator

Google Authenticator

工作原理

应用一个密钥和以后工夫戳来获取一个六位的一次性明码。
应用的算法:TOTP(Time-Based One-Time Password基于工夫的一次性明码)
举个栗子:例如应用密钥为DPI45HKISEXU6HG7,那么Google Authenticator会依据你刚刚输出的密钥和以后的工夫戳通过算法来获取一个一次性的明码。

应用办法:

1.下载:下载到google插件中
2.获取以后的密钥:本我的项目是应用base32加密获取:

this.token = base32.encodeAsString(appProperties.getToken().getBytes());

对于以后我的项目,那么如何获取加密后的密钥呢:base32 online

2.点击加号新建,能够抉择手动输出验证码或者通过二维码形式输出:

启用Authenticator在我的项目中

1.在pom.xml引入依赖,从新加载

        <!--one time password-->        <dependency>            <groupId>com.j256.two-factor-auth</groupId>            <artifactId>two-factor-auth</artifactId>            <version>1.3</version>        </dependency>

2.调用现成的TOTP算法生成一次性明码

public OneTimePasswordImpl(AppProperties appProperties) {    // 将token应用base32进行转码,原理同base64    Base32 base32 = new Base32();    this.token = base32.encodeAsString(appProperties.getToken().getBytes());  }/**   * 仅容许获取1次,获取胜利后code值为null   *   * @return   */  @Override  public Optional<String> getPassword() {    try {      // 间接调用现成库的办法生成一次性明码      String password = TimeBasedOneTimePasswordUtil.generateCurrentNumberString(this.token);      // 每个明码只能用一次,如果生成的明码与以后的明码雷同,则阐明短时间内申请了两次,返回empty      if (password.equals(this.password)) {        return Optional.empty();      } else {        this.password = password;      }    } catch (GeneralSecurityException e) {      this.logger.error("生成一次性明码时产生谬误");      e.printStackTrace();    }    return Optional.of(this.password);  }

3.建设本人的明码校验器

/** * 自定义明码校验器. * 留神:其不可能申明为@Component组件呈现,否则将触发DaoAuthenticationProvider的构造函数 * 从而间接注册DelegatingPasswordEncoder校验器 */public class MyBCryptPasswordEncoder extends BCryptPasswordEncoder {  private final Logger logger = LoggerFactory.getLogger(this.getClass());  /**   * 一次性明码.   */  private final OneTimePassword oneTimePassword;  public MyBCryptPasswordEncoder(OneTimePassword oneTimePassword) {    super();    this.oneTimePassword = oneTimePassword;  }  @Override  public boolean matches(CharSequence rawPassword, String encodedPassword) {    if (rawPassword == null) {      throw new IllegalArgumentException("rawPassword cannot be null");    }    // 当有一次性明码(每个明码仅能用一次)且未应用时,验证用户是否输出了超密    Optional oneTimePassword = this.oneTimePassword.getPassword();    // 判断是否应用一次性明码(如果明码等于通过算法获取的一次性明码,那么以后为应用超级明码登陆    if (oneTimePassword.isPresent() && oneTimePassword.get().equals(rawPassword.toString())) {      logger.warn("以后正在应用超级明码登录");      return true;    }    // 不应用超密则执行失常的明码判断    return super.matches(rawPassword, encodedPassword);  }}

4.应用本人建设的明码校验器替换默认的

@Configuration@EnableWebSecuritypublic class MvcSecurityConfig extends WebSecurityConfigurerAdapter {  private final BCryptPasswordEncoder passwordEncoder;  public MvcSecurityConfig(OneTimePassword oneTimePassword) {    this.passwordEncoder = new MyBCryptPasswordEncoder(oneTimePassword);    User.setPasswordEncoder(this.passwordEncoder);  }  @Bean  PasswordEncoder passwordEncoder() {    return this.passwordEncoder;  }}

5.验证是否胜利

间接应用Authenticator生成的明码进行登录测试:

右下角标注的是剩余时间,该一次性明码是每个肯定工夫刷新(如同是60秒)。

总结

此次弄超级明码还是破费本人肯定工夫的,起因在于办法不对,当接到工作之后就间接复制粘贴,而后去查原理,然而没有认真去看复制的代码的意思和思路。最初的后果就是事倍功半吧。