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获取更多资讯