共计 3424 个字符,预计需要花费 9 分钟才能阅读完成。
1. 前言
欢送浏览 Spring Security 实战干货系列文章,在集成 Spring Security 平安框架的时候咱们最先解决的可能就是依据咱们我的项目的理论须要来定制注册登录了,尤其是 Http 登录认证。依据以前的相干文章介绍,Http登录认证由过滤器UsernamePasswordAuthenticationFilter
进行解决。咱们只有把这个过滤器搞清楚能力做一些定制化。明天咱们就简略剖析它的源码和工作流程。
2. UsernamePasswordAuthenticationFilter 源码剖析
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;}
}
为了增强对流程的了解,我特意画了一张图来对这个流程进行清晰的阐明:
3. 咱们能够定制什么
依据下面的流程,咱们了解了 UsernamePasswordAuthenticationFilter
工作流程后能够做这些事件:
- 定制咱们的登录申请 URI 和申请形式。
- 登录申请参数的格局定制化,比方能够应用 JSON 格局提交甚至几种并存。
- 如何将用户名和明码封装入凭据
UsernamePasswordAuthenticationToken
,定制业务场景须要的非凡凭据。
4. 咱们会有什么疑难
AuthenticationManager
从哪儿来,它又是什么,它是如何对凭据进行认证的,认证胜利的后续细节是什么,认证失败的后续细节是什么。不要走开,继续关注:码农小胖哥 为你揭晓这个答案。
关注公众号:Felordcn 获取更多资讯
集体博客:https://felord.cn