SpringCloud微服务实战——搭建企业级开发框架(二十三):Gateway+OAuth2+JWT实现微服务统一认证授权 (10)

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增加账号判断

// 从Redis获取账号密码错误次数 Object lockTimes = redisTemplate.boundValueOps(AuthConstant.LOCK_ACCOUNT_PREFIX + gitEggUser.getId()).get(); // 判断账号密码输入错误几次,如果输入错误多次,则锁定账号 // 输入错误大于配置的次数,必须选择captcha或sms_captcha if (null != lockTimes && (int)lockTimes >= maxNonCaptchaTimes && ( StringUtils.isEmpty(authGrantType) || (!StringUtils.isEmpty(authGrantType) && !AuthEnum.SMS_CAPTCHA.code.equals(authGrantType) && !AuthEnum.CAPTCHA.code.equals(authGrantType)))) { throw new GitEggOAuth2Exception(ResultCodeEnum.INVALID_PASSWORD_CAPTCHA.msg); } // 判断账号是否被锁定(账户过期,凭证过期等可在此处扩展) if(null != lockTimes && (int)lockTimes >= maxTryTimes){ throw new LockedException(ResultCodeEnum.PASSWORD_TRY_MAX_ERROR.msg); } // 判断账号是否被禁用 String userStatus = gitEggUser.getStatus(); if (String.valueOf(GitEggConstant.DISABLE).equals(userStatus)) { throw new DisabledException(ResultCodeEnum.DISABLED_ACCOUNT.msg); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzjgjz.html