欢迎阅读Spring Security 实战干货系列文章,在集成Spring Security安全框架的时候咱们最早处理的可能就是根据咱们项目的实际须要来定制注册登陆了,尤为是Http登陆认证。根据之前的相关文章介绍,Http登陆认证由过滤器UsernamePasswordAuthenticationFilter
进行处理。咱们只有把这个过滤器搞清楚才能作一些定制化。今天咱们就简单分析它的源码和工做流程。java
UsernamePasswordAuthenticationFilter
继承于AbstractAuthenticationProcessingFilter
(另文分析)。它的做用是拦截登陆请求并获取帐号和密码,而后把帐号密码封装到认证凭据UsernamePasswordAuthenticationToken
中,而后把凭据交给特定配置的AuthenticationManager
去做认证。源码分析以下:安全
public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter { // 默认取帐户名、密码的key public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username"; public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password"; // 能够经过对应的set方法修改 private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY; private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY; // 默认只支持 POST 请求 private boolean postOnly = true; // 初始化一个用户密码 认证过滤器 默认的登陆uri 是 /login 请求方式是POST public UsernamePasswordAuthenticationFilter() { super(new AntPathRequestMatcher("/login", "POST")); } // 实现其父类 AbstractAuthenticationProcessingFilter 提供的钩子方法 用去尝试认证 public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { // 判断请求方式是不是POST if (postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException( "Authentication method not supported: " + request.getMethod()); } // 先去 HttpServletRequest 对象中获取帐号名、密码 String username = obtainUsername(request); String password = obtainPassword(request); if (username == null) { username = ""; } if (password == null) { password = ""; } username = username.trim(); // 而后把帐号名、密码封装到 一个认证Token对象中,这是就是一个通行证,可是这时的状态时不可信的,一旦经过认证就变为可信的 UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken( username, password); // 会将 HttpServletRequest 中的一些细节 request.getRemoteAddr() request.getSession 存入的到Token中 setDetails(request, authRequest); // 而后 使用 父类中的 AuthenticationManager 对Token 进行认证 return this.getAuthenticationManager().authenticate(authRequest); } // 获取密码 很重要 若是你想改变获取密码的方式要么在此处重写,要么经过自定义一个前置的过滤器保证能此处能get到 @Nullable protected String obtainPassword(HttpServletRequest request) { return request.getParameter(passwordParameter); } // 获取帐户很重要 若是你想改变获取密码的方式要么在此处重写,要么经过自定义一个前置的过滤器保证能此处能get到 @Nullable protected String obtainUsername(HttpServletRequest request) { return request.getParameter(usernameParameter); } // 参见上面对应的说明为凭据设置一些请求细节 protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } // 设置帐户参数的key public void setUsernameParameter(String usernameParameter) { Assert.hasText(usernameParameter, "Username parameter must not be empty or null"); this.usernameParameter = usernameParameter; } // 设置密码参数的key public void setPasswordParameter(String passwordParameter) { Assert.hasText(passwordParameter, "Password parameter must not be empty or null"); this.passwordParameter = passwordParameter; } // 认证的请求方式是只支持POST请求 public void setPostOnly(boolean postOnly) { this.postOnly = postOnly; } public final String getUsernameParameter() { return usernameParameter; } public final String getPasswordParameter() { return passwordParameter; } }
为了增强对流程的理解,我特地画了一张图来对这个流程进行清晰的说明:框架
根据上面的流程,咱们理解了UsernamePasswordAuthenticationFilter
工做流程后能够作这些事情:源码分析
UsernamePasswordAuthenticationToken
,定制业务场景须要的特殊凭据。AuthenticationManager
从哪儿来,它又是什么,它是如何对凭据进行认证的,认证成功的后续细节是什么,认证失败的后续细节是什么。不要走开,持续关注:码农小胖哥 为你揭晓这个答案。post
关注公众号:Felordcn 获取更多资讯
ui