SpringSecurity进行json对象传参实现手机验证码登录

在对security进行用户名密码登录之后还要满足手机验证码登录,由于是初次使用security进行手机验证,并且由于前端用的json对象进行传参,导致在验证时出现了一些问题。由于在网上也没查到使用json对象进行手机验证的操作,于是自己便根据用户名密码登录的操作进行了一些改写。

继承AbstractAuthenticationProcessingFilter

private String mobileParameter = "mobile";

private String smsCodeParameter = "smsCode";

private boolean postOnly = true;

protected SmsCodeAuthenticationFilter() {
    // 请求接口的url
    super(new AntPathRequestMatcher("/user/phone", "POST"));
}

@Override
public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
    if(httpServletRequest.getContentType() != null && (httpServletRequest.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE)
            || httpServletRequest.getContentType().equals(MediaType.APPLICATION_JSON_VALUE))) {
        ObjectMapper mapper = new ObjectMapper();
        SmsCodeAuthenticationToken authRequest = null;

        try (InputStream is = httpServletRequest.getInputStream() ) {
            Map<String, String> authenticationBean = mapper.readValue(is, Map.class);
            authRequest = new SmsCodeAuthenticationToken(authenticationBean.get("mobile"), authenticationBean.get("smsCode"));
        } catch (IOException e) {
            e.printStackTrace();
            authRequest = new SmsCodeAuthenticationToken("", "");
        }finally {
            setDetails(httpServletRequest,authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    } else {
        if (postOnly && !httpServletRequest.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + httpServletRequest.getMethod());
        } else {
            //根据请求参数名,获取请求value
            String mobile = obtainMobile(httpServletRequest);
            String smsCode = obtainSmsCode(httpServletRequest);
            logger.info("mobile:{}", mobile);

            if (mobile == null) {
                mobile = "";
            }
            mobile = mobile.trim();

            // 生成对应的AuthenticationToken
            SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(mobile, smsCode);

            setDetails(httpServletRequest, authRequest);

            return this.getAuthenticationManager().authenticate(authRequest);
        }
    }
}

@Nullable
protected String obtainMobile(HttpServletRequest request) {
    return request.getParameter(mobileParameter);
}

@Nullable
protected String obtainSmsCode(HttpServletRequest request) {
    return request.getParameter(smsCodeParameter);
}

protected void setDetails(HttpServletRequest request, SmsCodeAuthenticationToken authRequest) {
    authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
}

实现 AuthenticationProvider

@Autowired
private SmsUserDetailsService smsUserDetailsService;

@Autowired
private RedisTemplate<Object, Object> redisTemplate;

/**
 * 身份逻辑验证
 * @param authentication
 * @return
 * @throws AuthenticationException*/
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;

    String mobile = (String) authenticationToken.getPrincipal();

    String smsCode = (String) authenticationToken.getCredentials();

    logger.info(mobile + ":" + smsCode);

    checkSmsCode(mobile,smsCode);

    UserDetails user = smsUserDetailsService.loadUserByUsername(mobile);
    if (user == null) {
        throw new BadCredentialsException("无法获取用户信息");
    }

    SmsCodeAuthenticationToken authenticationResult = new SmsCodeAuthenticationToken(user, user.getAuthorities());

    authenticationResult.setDetails(authenticationToken.getDetails());

    return authenticationResult;

}

private void checkSmsCode(String mobile , String inputCode) {
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

    if (redisTemplate == null) {
        throw new BadCredentialsException("未检测到申请验证码");
    }

    String smsCode = (String) redisTemplate.opsForValue().get(mobile);
    System.out.println(smsCode);
    if(smsCode == null) {
        throw new BadCredentialsException("未检测到申请验证码");
    }

    if(smsCode == null ){
        throw new BadCredentialsException("验证码已失效");
    }
    if(!smsCode.equals(inputCode)) {
        throw new BadCredentialsException("验证码错误");
    }
}

@Override
public boolean supports(Class<?> authentication) {
    return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
}

public SmsUserDetailsService getSmsUserDetailsService() {
    return smsUserDetailsService;
}

public void setSmsUserDetailsService(SmsUserDetailsService smsUserDetailsService) {
    this.smsUserDetailsService = smsUserDetailsService;
}

继承AbstractAuthenticationToken

private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

private final Object principal;

private Object credentials;

public SmsCodeAuthenticationToken(Object principal, Object credentials) {
    super((Collection)null);
    this.principal = principal;
    this.credentials = credentials;
    this.setAuthenticated(false);
}

public SmsCodeAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
    super(authorities);
    this.principal = principal;
    this.credentials = credentials;
    super.setAuthenticated(true);
}


@Override
public Object getCredentials() {
    return this.credentials;
}

@Override
public Object getPrincipal() {
    return this.principal;
}

public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
    if (isAuthenticated) {
        throw new IllegalArgumentException(
                "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
    }
    super.setAuthenticated(false);
}

@Override
public void eraseCredentials() {
    super.eraseCredentials();
}

配置securityConfig

http.addFilterAt(smsCodeAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class).authenticationProvider(smsCodeAuthenticationProvider);
    http.addFilterAt(myAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class).authenticationProvider(userAuthenticationProvider);

/******************************/

@Bean
MyAuthenticationFilter myAuthenticationFilter() throws Exception {
    MyAuthenticationFilter filter = new MyAuthenticationFilter();
    filter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler);
    filter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);
    filter.setAuthenticationManager(authenticationManagerBean());
    return filter;
}

@Bean
SmsCodeAuthenticationFilter smsCodeAuthenticationFilter() throws Exception {
    SmsCodeAuthenticationFilter filter = new SmsCodeAuthenticationFilter();
    filter.setAuthenticationSuccessHandler(smsAuthenticationSuccessHandler);
    filter.setAuthenticationFailureHandler(smsAuthenticationFailureHandler);
    filter.setAuthenticationManager(authenticationManagerBean());
    return filter;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值