spring boot超级密码登陆

序言

在测试的时候,当其他人修改了某一个用户密码,那么想要登陆该用户进行测试则需要重置数据库,那么此时需要增加一种特殊的登陆方式,不依靠账户: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.点击加号新建,可以选择手动输入验证码或者通过二维码方式输入:
image.png
image.png

启用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
@EnableWebSecurity
public 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生成的密码进行登录测试:
image.png
右下角标注的是剩余时间,该一次性密码是每个一定时间刷新(好像是60秒)。

总结

此次弄超级密码还是花费自己一定时间的,原因在于方法不对,当接到任务之后就直接复制粘贴,然后去查原理,但是没有仔细去看复制的代码的意思和思路。最后的结果就是事半功倍吧。

167 声望
15 粉丝
0 条评论
推荐阅读
Springboot实现文件上传和下载
在一些文件存储量很小的工程中,有一些上传文件放置在工程本身的目录下,但是随着文件上传的量越来越大,工程本身所在的文件夹容量会越来越大,不仅打包和部署的效率会降低,工程的启动和运行也会变慢,所以一般...

郝泽龙_HZ2阅读 657

图解浏览器的多进程渲染机制
观察浏览器的任务管理器可以发现,打开浏览器的一个页面需要多个进程,包括浏览器进程、GPU 进程、网络进程、渲染进程等,有插件的话还会包括各种插件进程(Chrome 选项 -&gt; 更多工具 -&gt; 任务管理器)。

兰俊秋雨6阅读 1.1k

前端性能指标
传统性能标准初始化阶段navigationStart:请求开始时间,返回 0unloadEventStart:等于用户代理程序开始前一个文档的卸载事件之前的时间unloadEventEnd:等于用户代理程序完成前一文档的卸载事件之后的时间redire...

散一群逗逼9阅读 1.2k

封面图
编写属于自己的音乐播放器
因为以上两个问题,这就导致我们需要对原生的audio进行修改时比较困难。而对于大多数音频的需求,我们可以使用满足我们要求的第三方组件库中选择,如:

九旬7阅读 673评论 1

angular 中ActivatedRoute 和 Router,以及记录后台遇到的问题
ActivatedRoute 和 Router的区别前台angular使用这两个来进行路由的操作,但是好像一直不大清楚区别。这里简单记录一下。区别 {代码...} ActivatedRoute是当前组件的路由对象,包含了当前的路由信息。router是全...

weiweiyi6阅读 1.3k

记录java 在遍历中删除元素 以及 mysql5.6版本添加unique失败
遍历中删除List或Queue等数据结构中,如何一边遍历一遍删除?1. 常犯错误ArrayList可能没遇到坑过的人会用增强for循环这么写: {代码...} 但是一运行,结果却抛 java.util.ConcurrentModificationException 异常即...

weiweiyi6阅读 955

学会了slidev.js的开发者, 也许可以考虑不用ppt了?
&ensp;&ensp;&ensp; 作为一个开发者, 每次使用PPT或者Word写简历或者述职都好痛苦啊, 这些App也不太适合展示代码, 但是今天来的家人们有福了, 一款叫做是slidev的库露出了邪魅的微笑 官网地址。

lulu_up6阅读 553

167 声望
15 粉丝
宣传栏