大继的基础级业务实战设计记录(四),谷歌令牌

2018-07-21  本文已影响0人  大继

场景描述

满足

主要实现

  1. 发行一个用户密钥
  2. 通过旧密钥更新密钥 http://google/authenticates GoogleAuthenticateUserRefreshRequest
  3. 用户向 http://google/authenticates GoogleAuthenticateUserRequest 验证动态码是否正确
  4. 强行更新密钥 PUT http://google/authenticates/xxx GoogleAuthenticate (用于后台管理,或通过手机验证码等更高权重的验证进行刷新或修改)

范围

一个用户只能绑定一个证明 authenticate.

restful设计

TOTP 实现

发行

public GoogleAuthenticate release(Long userId, String account) {

        if(googleAuthenticateRepository.findByUserId(userId) == null){
            GoogleAuthenticate googleAuthenticate = new GoogleAuthenticate();

            googleAuthenticate.setId(UUID.randomUUID().toString());
            googleAuthenticate.setCreateTime(new Date());
            googleAuthenticate.setEnable(true);
            googleAuthenticate.setIssuer(ISSUER);
            googleAuthenticate.setAccount(account);
            googleAuthenticate.setKey(randomSecretKey());
            googleAuthenticate.setUserId(userId);
            googleAuthenticateRepository.save(googleAuthenticate);

            return googleAuthenticate;
        }else {
            throw new RuntimeException("User had already released authenticate.");
        }
    }

验证

public Boolean validate(Long userId, String code) {
        Boolean isAuthenticate = false;

        //连续错误次数  6/1 (次/天) 锁定用户
        GoogleAuthenticateWrongDaliyLog googleAuthenticateWrongDaliyLog =
                googleAuthenticateWrongDailyLogRepository.findByUserIdAndDay(userId,
                        new java.sql.Date(System.currentTimeMillis()));
        if(googleAuthenticateWrongDaliyLog != null &&  googleAuthenticateWrongDaliyLog.getWrongTimes() > 6){
            return false;
        }

        GoogleAuthenticate googleAuthenticate = googleAuthenticateRepository.findByUserId(userId);
        if(googleAuthenticate != null){
            //check
            if(code.equals(getTOTPCode(googleAuthenticate.getKey()))){
                isAuthenticate = true;
            }

        }

        if(!isAuthenticate){
            if(googleAuthenticateWrongDaliyLog == null){
                googleAuthenticateWrongDaliyLog = new GoogleAuthenticateWrongDaliyLog();
                googleAuthenticateWrongDaliyLog.setDay(new java.sql.Date(System.currentTimeMillis()));
                googleAuthenticateWrongDaliyLog.setUserId(userId);
                googleAuthenticateWrongDaliyLog.setWrongTimes(0);
            }
            googleAuthenticateWrongDaliyLog.setWrongTimes(googleAuthenticateWrongDaliyLog.getWrongTimes() + 1);
            googleAuthenticateWrongDailyLogRepository.save(googleAuthenticateWrongDaliyLog);
        }

        return isAuthenticate;
    }

实体设计

@Entity
@Table(name = "google_authenticate",
        indexes = {@Index(columnList = "userId",unique = true)})
public class GoogleAuthenticate {

    @Id
    @Column(length = 37)
    private String id;

    @Column
    private String account;

    @Column(length = 64)
    private String key;

    @Column
    private String issuer;

    @Column
    private Long userId;

    /**
     * 用于锁定用户,如果过于频繁,验证失败。
     */
    @Column
    private Boolean enable;

    @Column
    private Date updateTime;

    @Column
    private Date createTime;
}

验证

@Test
    public void releaseTest(){
        GoogleAuthenticate googleAuthenticate = googleAuthenticateService.release(0L,"daji@qq.com");

        //把输出放,草料生成二维码,导入到 google authenticator
        System.out.println(googleAuthenticateService.produceQrCode(googleAuthenticate));
    }

输出

otpauth://totp/hitstone.cn%3Adaji%40qq.com?secret=3HOKVR3YIM3YXCCOB3WSU34COBFA5MBH&issuer=hitstone.cn
//导入到 google authenticator
image.png
@Test
    public void checkCodeTest(){
        String code = "047345"; //查看google authenticator 填入,并认证。

        System.out.println(googleAuthenticateService.validate(0L,code));
    }

输出

true

由于写的比较冲忙,只对思路进行描述。

参考

上一篇 下一篇

猜你喜欢

热点阅读