oauth2对用户状态进行修改与校验(一) 您所在的位置:网站首页 接收行不在登陆状态 oauth2对用户状态进行修改与校验(一)

oauth2对用户状态进行修改与校验(一)

2024-07-16 10:41| 来源: 网络整理| 查看: 265

项目中登录的时候使用的是oauth2获取token进行登录,最近要加入账户锁定机制,连续输错几次密码以后锁定一段时间,如果连续错误次数太多则冻结。

梳理了一下功能:

用户状态分为四种:正常、暂时封禁、冻结、停用(停用是人员离职一类的,将账号停用)登录时,先获取用户状态,若非正常用户则直接提示对应信息登录失败时,需要能够进入自定义的失败方法,对用户账户失败次数+1,记录本次登录时间,修改用户状态(若需要)登录成功时,将用户状态修改为正常,连续错误次数置0,记录登录时间。 监听登录成功/失败方法

参考链接:spring-security-oauth2 登录或者认证成功后 做一些操作, 比如登录日志

把源码记录一下,主要的认证方法

在ResourceOwnerPasswordTokenGranter类的getOAuth2Authentication方法中获取用户名与密码,进入authenticate方法校验 @Override protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) { Map parameters = new LinkedHashMap(tokenRequest.getRequestParameters()); // 获取用户名&密码 String username = parameters.get("username"); String password = parameters.get("password"); // 拿完密码就移除 parameters.remove("password"); Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password); ((AbstractAuthenticationToken) userAuth).setDetails(parameters); try { // 在这个方法里面进行用户认证,以及成功/失败的事件发布 userAuth = authenticationManager.authenticate(userAuth); } catch (AccountStatusException ase) { // ... } // 省略... 接着进入ProviderManager的authenticate方法 public Authentication authenticate(Authentication authentication) throws AuthenticationException { // ... // 提供了一系列AuthenticationProvider进行验证 for (AuthenticationProvider provider : getProviders()) { // .... try { // 认证 result = provider.authenticate(authentication); // ... } catch (AccountStatusException e) { // 捕获异常,注意这个方法,里面会发布失败事件 prepareException(e, authentication); throw e; } catch (InternalAuthenticationServiceException e) { // 捕获异常,注意这个方法,里面会发布失败事件 prepareException(e, authentication); throw e; } catch (AuthenticationException e) { lastException = e; } } // ... if (result != null) { // ... if (parentResult == null) { // 发布登录成功事件 eventPublisher.publishAuthenticationSuccess(result); } return result; } throw lastException; } @SuppressWarnings("deprecation") private void prepareException(AuthenticationException ex, Authentication auth) { // 在此处发布认证失败事件 eventPublisher.publishAuthenticationFailure(ex, auth); }

由于这两个事件的发布,因此可以实现ApplicationListener来获取到登录成功与失败

登录成功: @Component public class SuccessEvent implements ApplicationListener { @Autowired private UserDetailsServiceMapper userDetailsServiceMapper; /** * 获取token成功事件 * @param event */ @Override public void onApplicationEvent(AuthenticationSuccessEvent event) { if (!event.getSource().getClass().getName().equals("org.springframework.security.authentication.UsernamePasswordAuthenticationToken")) { return; } if (event.getAuthentication().getPrincipal() instanceof JdbcUserDetails) { // 这个方式稍微有一点麻烦,不止是登陆事件,一些其他的事件,包括自定义的filter也可能进入该方法 // 所以需要这些判断保证只有用户登录成功才进入这里。 JdbcUserDetails userDetails = (JdbcUserDetails) event.getAuthentication().getPrincipal(); User user = userDetailsServiceMapper.selectUserById(Long.valueOf(userDetails.getUserId())); // 更新用户状态 updateUserAccountById(user); } } }

登录失败与成功类似,可以直接implement失败事件,这里换了种方式,直接监听AuthenticationFailureBadCredentialsEvent 异常。

有点神奇,没有仔细看源码,感觉上是filter与oauth是分了两部分的。在自定义filter中抛出该异常并不会被监听到,需要继承BasicErrorController来捕获,这里不写了,只有获取token相关流程的异常会被这个类监听到。 登录失败 @Component public class failureEvents { /** * @param failure */ @EventListener public void onFailure(AuthenticationFailureBadCredentialsEvent failure) { if (failure == null) { return; } if (failure.getSource() instanceof UsernamePasswordAuthenticationToken) { UsernamePasswordAuthenticationToken authenticationToken = (UsernamePasswordAuthenticationToken) failure.getSource(); LinkedHashMap details = (LinkedHashMap) authenticationToken.getDetails(); // 更新用户状态 updateUserAccount(username); } } } 后面还有一部分,是发送请求后,应该第一步做用户状态的检查及异常返回,这里踩坑了,有空再写~


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有