文章
问答
冒泡
Spring Security短信登录实现(五)

组件Filter、Provider、AuthenticationToken

SmsCodeAuthenticationFilter.java

	public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
	
	    private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("/sms/login",
	            "POST");
	
	    public SmsCodeAuthenticationFilter(AuthenticationManager authenticationManager) {
	        super(DEFAULT_ANT_PATH_REQUEST_MATCHER);
	        setAuthenticationManager(authenticationManager);
	    }
	
	    @Override
	    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
	        String mobile = request.getParameter("mobile");
	        String code = request.getParameter("code");
	
	        SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(mobile, code);
	        setDetails(request, authRequest);
	        return this.getAuthenticationManager().authenticate(authRequest);
	    }
	
	    protected void setDetails(HttpServletRequest request, SmsCodeAuthenticationToken authRequest) {
	        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
	    }
}

SmsCodeAuthenticationToken.java

	public class SmsCodeAuthenticationToken extends AbstractAuthenticationToken {
	
	    private String mobile;
	
	    private String code;
	
	    public SmsCodeAuthenticationToken(String mobile, String code) {
	        super(null);
	        this.mobile = mobile;
	        this.code = code;
	        setAuthenticated(false);
	    }
	
	    public SmsCodeAuthenticationToken(String mobile, String code,
	                                               Collection<? extends GrantedAuthority> authorities) {
	        super(authorities);
	        this.mobile = mobile;
	        this.code = code;
	        super.setAuthenticated(true); // must use super, as we override
	    }
	
	    @Override
	    public Object getCredentials() {
	        return this.code;
	    }
	
	    @Override
	    public Object getPrincipal() {
	        return this.mobile;
	    }
	}

SmsCodeAuthenticationProvider.java

@AllArgsConstructor
public class SmsCodeAuthenticationProvider implements AuthenticationProvider {

    private UserDetailsService userDetailsService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String mobile = (String)authentication.getPrincipal();
        String code = (String) authentication.getCredentials();
        // TODO 验证码
        validate(mobile, code);

        UserDetails userDetails = userDetailsService.loadUserByUsername(mobile);
        SmsCodeAuthenticationToken successAuthentication = new SmsCodeAuthenticationToken(userDetails.getUsername(),
                userDetails.getPassword(), userDetails.getAuthorities());

        return successAuthentication;
    }

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

    private void validate(String mobile, String code) {
        if (!"888888".equals(code)) {
            throw new BadCredentialsException("验证码不正确!");
        }
    }

}

添加到配置

  • 添加Provider

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(new SmsCodeAuthenticationProvider(username -> new User("jkxyx205", "11", AuthorityUtils.commaSeparatedStringToAuthorityList("USER"))));
    }
  • 添加Filter

    @Override
    protected void configure(HttpSecurity http) throws Exception {
	    http.addFilterBefore(new SmsCodeAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);
    }

测试页面

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
>
<head>
    <meta charset="UTF-8">
    <title>自定义登录</title>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.0.2/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div style="margin: 40px auto; width: 320px;">
        <th:block th:if="${session.SPRING_SECURITY_LAST_EXCEPTION != null}">
            <div th:text="${session.SPRING_SECURITY_LAST_EXCEPTION.message}"></div>
        </th:block>
        <form action="/sms/login" method="post">
            <div class="mb-3 row">
                <label for="mobile" class="visually-hidden">用户名</label>
                <input type="text" class="form-control" id="mobile" name="mobile" value="18898987724">
            </div>
            <div class="mb-3 row">
                <label for="code" class="visually-hidden">手机验证码</label>
                <input type="text" class="form-control" id="code" name="code" value="888888">
            </div>
            <div class="mb-3 row">
                <button type="submit" class="btn btn-primary mb-3">登录</button>
            </div>
        </form>
    </div>
</body>
</html>

启动日志

2021-10-10 12:41:07.188  INFO 54574 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@4694f434, org.springframework.security.web.context.SecurityContextPersistenceFilter@ceddaf8, org.springframework.security.web.header.HeaderWriterFilter@5f174dd2, org.springframework.security.web.authentication.logout.LogoutFilter@608b1fd2, com.rick.security.authentication.sms.SmsCodeAuthenticationFilter@56928e17, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@6dc1dc69, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@4833eff3, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@1db87583, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@6993c8df, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@dd2856e, org.springframework.security.web.session.SessionManagementFilter@45aca496, org.springframework.security.web.access.ExceptionTranslationFilter@10a98392, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@70c69586]

SmsCodeAuthenticationFilter 已经添加到了 DefaultSecurityFilterChain


关于作者

Rick
获得点赞
文章被阅读