1. 前言 欢迎阅读Spring Security 实战干货系列文章,在集成Spring Security 安全框架的时候我们最先处理的可能就是根据我们项目的实际需要来定制注册登录了,尤其是Http 登录认证。根据以前的相关文章介绍,Http 登录认证由过滤器UsernamePasswordAuthenticationFilter
进行处理。我们只有把这个过滤器搞清楚才能做一些定制化。今天我们就简单分析它的源码和工作流程。
2. UsernamePasswordAuthenticationFilter 源码分析 UsernamePasswordAuthenticationFilter
继承于AbstractAuthenticationProcessingFilter
(另文分析)。它的作用是拦截登录请求并获取账号和密码,然后把账号密码封装到认证凭据UsernamePasswordAuthenticationToken
中,然后把凭据交给特定配置的AuthenticationManager
去作认证。源码分析如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter { public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username" ; public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password" ; private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY; private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY; private boolean postOnly = true ; public UsernamePasswordAuthenticationFilter () { super (new AntPathRequestMatcher ("/login" , "POST" )); } public Authentication attemptAuthentication (HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (postOnly && !request.getMethod().equals("POST" )) { throw new AuthenticationServiceException ( "Authentication method not supported: " + request.getMethod()); } String username = obtainUsername(request); String password = obtainPassword(request); if (username == null ) { username = "" ; } if (password == null ) { password = "" ; } username = username.trim(); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken ( username, password); setDetails(request, authRequest); return this .getAuthenticationManager().authenticate(authRequest); } @Nullable protected String obtainPassword (HttpServletRequest request) { return request.getParameter(passwordParameter); } @Nullable protected String obtainUsername (HttpServletRequest request) { return request.getParameter(usernameParameter); } protected void setDetails (HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } public void setUsernameParameter (String usernameParameter) { Assert.hasText(usernameParameter, "Username parameter must not be empty or null" ); this .usernameParameter = usernameParameter; } public void setPasswordParameter (String passwordParameter) { Assert.hasText(passwordParameter, "Password parameter must not be empty or null" ); this .passwordParameter = passwordParameter; } public void setPostOnly (boolean postOnly) { this .postOnly = postOnly; } public final String getUsernameParameter () { return usernameParameter; } public final String getPasswordParameter () { return passwordParameter; } }
为了加强对流程的理解,我特意画了一张图来对这个流程进行清晰的说明:
3. 我们可以定制什么 根据上面的流程,我们理解了UsernamePasswordAuthenticationFilter
工作流程后可以做这些事情:
定制我们的登录请求URI和请求方式。
登录请求参数的格式定制化,比如可以使用JSON 格式提交甚至几种并存。
将用户名和密码封装入凭据UsernamePasswordAuthenticationToken
,定制业务场景需要的特殊凭据。
4. 我们会有什么疑问 AuthenticationManager
从哪儿来,它又是什么,它是如何对凭据进行认证的,认证成功的后续细节是什么,认证失败的后续细节是什么。不要走开,持续关注为你揭晓这个答案。
转载自@felord.cn