主要就是 增加安全性,类似于 短信二次验证一样,不过Google 二次验证 提供的是开源一套算法,节约成本,很多网站为了真加安全性,都开启了二次验证 。
java 具体思路
- 网站或者服务端 开启二次验证 ,引入开源工具包
编写对应的工具类,生成二维码链接,用户扫描绑定 秘钥key
自定义 AuthenticationProvider,UsernamePasswordAuthenticationToken 在校验完用户密码后再 处理 google 校验逻辑
代码
- 修改配置SpringSecurity
httpSecurity.authenticationProvider(new CustomerAuthenticationProvider(userDetailsService,bCryptPasswordEncoder()));
-
自定义 CustomerAuthenticationProvider,CustomerUsernamePasswordAuthenticationToken 直接继承重写父类方法就行
public class CustomerAuthenticationProvider extends DaoAuthenticationProvider { public CustomerAuthenticationProvider(UserDetailsService userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) { super(); setUserDetailsService(userDetailsService); setPasswordEncoder(bCryptPasswordEncoder); } protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { if (authentication.getCredentials() == null) { this.logger.debug("Failed to authenticate since no credentials provided"); throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } else { String presentedPassword = authentication.getCredentials().toString(); if (!getPasswordEncoder().matches(presentedPassword, userDetails.getPassword())) { this.logger.debug("Failed to authenticate since password does not match stored value"); throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } googleAuthenticator((LoginUser) userDetails, (CustomerUsernamePasswordAuthenticationToken) authentication); } } /** * Google 二次验证 * @param userDetails * @param authentication */ private void googleAuthenticator(LoginUser userDetails, CustomerUsernamePasswordAuthenticationToken authentication) { // Google 二次验证 LoginUser loginUser = userDetails; SysUser user = loginUser.getUser(); String googleAuthSecret = user.getGoogleAuthSecret(); if(StringUtils.isBlank(googleAuthSecret)){ throw new ServiceException(GOOGLE_AUTHENTICATOR_401001.getMsg(),GOOGLE_AUTHENTICATOR_401001.getCode()); } CustomerUsernamePasswordAuthenticationToken customerToken = authentication; String code = customerToken.getCode(); boolean valid = GoogleAuthenticatorUtils.valid(googleAuthSecret, Integer.valueOf(code).intValue()); if(!valid){ throw new ServiceException("Google Authenticator 验证码错误"); } } } public class CustomerUsernamePasswordAuthenticationToken extends UsernamePasswordAuthenticationToken { /** * Google 二次验证 生成 code */ private String code; public CustomerUsernamePasswordAuthenticationToken(Object principal, Object credentials) { super(principal, credentials); } public CustomerUsernamePasswordAuthenticationToken(Object principal, Object credentials,String code) { super(principal, credentials); this.code = code; } public CustomerUsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) { super(principal, credentials, authorities); } public String getCode() { return code; } public void setCode(String code) { this.code = code; } } // 调用自定义 CustomerUsernamePasswordAuthenticationToken authentication = authenticationManager .authenticate(new CustomerUsernamePasswordAuthenticationToken(username, password,code));