2、每次登录成功之后,根据是否勾选记住密码来确定是否填入用户名密码
// 判断是否记住密码 const rememberMe = this.form.getFieldValue('rememberMe') const username = this.form.getFieldValue('username') const password = this.form.getFieldValue('password') if (rememberMe && username !== '' && password !== '') { storage.set(process.env.VUE_APP_TENANT_ID + '-' + process.env.VUE_APP_CLIENT_ID + '-username', username, 60 * 60 * 24 * 7 * 1000) storage.set(process.env.VUE_APP_TENANT_ID + '-' + process.env.VUE_APP_CLIENT_ID + '-password', password, 60 * 60 * 24 * 7 * 1000) storage.set(process.env.VUE_APP_TENANT_ID + '-' + process.env.VUE_APP_CLIENT_ID + '-rememberMe', true, 60 * 60 * 24 * 7 * 1000) } else { storage.remove(process.env.VUE_APP_TENANT_ID + '-' + process.env.VUE_APP_CLIENT_ID + '-username') storage.remove(process.env.VUE_APP_TENANT_ID + '-' + process.env.VUE_APP_CLIENT_ID + '-password') storage.remove(process.env.VUE_APP_TENANT_ID + '-' + process.env.VUE_APP_CLIENT_ID + '-rememberMe') } 五、密码尝试次数过多则锁定账户从系统安全方面来讲,我们需要支持防止用户账户被暴力破解的措施,目前技术已经能够轻松破解大多数的验证码,这为暴力破解用户账户提供了方便,那么这里我们的系统需要密码尝试次数过多锁定账户的功能。SpringSecurity的UserDetails接口定义了isAccountNonLocked方法来判断账户是否被锁定
public interface UserDetails extends Serializable { Collection<!--? extends GrantedAuthority--> getAuthorities(); String getPassword(); String getUsername(); boolean isAccountNonExpired(); boolean isAccountNonLocked(); boolean isCredentialsNonExpired(); boolean isEnabled(); }1、自定义LoginFailureListener事件监听器,监听SpringSecurity抛出AuthenticationFailureBadCredentialsEvent异常事件,使用Redis计数器,记录账号错误密码次数
/** * 当登录失败时的调用,当密码错误过多时,则锁定账户 * @author GitEgg * @date 2021-03-12 17:57:05 **/ @Slf4j @Component @RequiredArgsConstructor(onConstructor_ = @Autowired) public class LoginFailureListener implements ApplicationListener<authenticationfailurebadcredentialsevent> { private final UserDetailsService userDetailsService; private final RedisTemplate redisTemplate; @Value("${system.maxTryTimes}") private int maxTryTimes; @Override public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent event) { if (event.getException().getClass().equals(UsernameNotFoundException.class)) { return; } String userName = event.getAuthentication().getName(); GitEggUserDetails user = (GitEggUserDetails) userDetailsService.loadUserByUsername(userName); if (null != user) { Object lockTimes = redisTemplate.boundValueOps(AuthConstant.LOCK_ACCOUNT_PREFIX + user.getId()).get(); if(null == lockTimes || (int)lockTimes <= maxTryTimes){ redisTemplate.boundValueOps(AuthConstant.LOCK_ACCOUNT_PREFIX + user.getId()).increment(GitEggConstant.Number.ONE); } } } }2、GitEggUserDetailsServiceImpl方法查询Redis记录的账号锁定次数
// 判断账号是否被锁定(账户过期,凭证过期等可在此处扩展) Object lockTimes = redisTemplate.boundValueOps(AuthConstant.LOCK_ACCOUNT_PREFIX + gitEggUser.getId()).get(); boolean accountNotLocked = true; if(null != lockTimes && (int)lockTimes >= maxTryTimes){ accountNotLocked = false; } 六、登录时是否需要输入验证码验证码设置前三次(可配置)登录时,不需要输入验证码,当密码尝试次数大于三次时,需要输入验证码,登录方式的一个思路:初始进入登录界面,用户可选择自己的登录方式,我们系统OAuth默认设置了三种登录方式:
用户名+密码登录
用户名+密码+验证码
手机号+验证码登录
系统默认采用用户名+密码登录,当默认的用户名密码登录错误次数(默认一次)超过系统配置的最大次数时,则必须输入验证码登录,当验证码也超过一定次数时(默认五次),都不行则锁定账户二小时之后才可以继续尝试。因为考虑到有些系统可能不会用到短信验证码等,所以这里作为一个扩展功能:如果有需要可以在用户名密码错误过多时,强制只用短信验证码才能登录,且一定要设置超过错误次数就锁定。
1、在自定义的GitEggUserDetailsServiceImpl增加账号判断