Spring Security 实战干货:图解用户是如何登录的

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 获取更多资讯
Spring Security 实战干货:图解用户是如何登录的的更多相关文章
- Spring Security 实战干货:实现自定义退出登录
文章目录 1. 前言 2. 我们使用 Spring Security 登录后都做了什么 2. 退出登录需要我们做什么 3. Spring Security 中的退出登录 3.1 LogoutFilte ...
- Spring Security 实战干货:图解Spring Security中的Servlet过滤器体系
1. 前言 我在Spring Security 实战干货:内置 Filter 全解析对Spring Security的内置过滤器进行了罗列,但是Spring Security真正的过滤器体系才是我们了 ...
- Spring Security 实战干货:AuthenticationManager的初始化细节
1. 前言 今天有个同学告诉我,在Security Learning项目的day11分支中出现了一个问题,验证码登录和其它登录不兼容了,出现了No Provider异常.还有这事?我赶紧跑了一遍还真是 ...
- Spring Security 实战干货:使用 JWT 认证访问接口
(转载)原文链接:https://my.oschina.net/10000000000/blog/3127268 1. 前言 欢迎阅读Spring Security 实战干货系列.之前我讲解了如何编写 ...
- Spring Security 实战干货: 简单的认识 OAuth2.0 协议
1.前言 欢迎阅读 Spring Security 实战干货 系列文章 .OAuth2.0 是近几年比较流行的授权机制,对于普通用户来说可能每天你都在用它,我们经常使用的第三方登录大都基于 OAuth ...
- Spring Security 实战干货:如何实现不同的接口不同的安全策略
1. 前言 欢迎阅读 Spring Security 实战干货 系列文章 .最近有开发小伙伴提了一个有趣的问题.他正在做一个项目,涉及两种风格,一种是给小程序出接口,安全上使用无状态的JWT Toke ...
- Spring Security 实战干货:理解AuthenticationManager
1. 前言 我们上一篇介绍了UsernamePasswordAuthenticationFilter的工作流程,留下了一个小小的伏笔,作为一个Servlet Filter应该存在一个doFilter实 ...
- Spring Security 实战干货:OAuth2第三方授权初体验
1. 前言 Spring Security实战干货系列 现在很多项目都有第三方登录或者第三方授权的需求,而最成熟的方案就是OAuth2.0授权协议.Spring Security也整合了OAuth2. ...
- Spring Security 实战干货:客户端OAuth2授权请求的入口
1. 前言 在Spring Security 实战干货:OAuth2第三方授权初体验一文中我先对OAuth2.0涉及的一些常用概念进行介绍,然后直接通过一个DEMO来让大家切身感受了OAuth2.0第 ...
随机推荐
- CSS选择器使用
今天要对CSS选择器的使用方法做一个全面的总结(几乎全部是从这篇文章摘抄的 https://blog.csdn.net/qq_39241986/article/details/82185697) CS ...
- 学习Java的Day04
知识点 接口: 1.接口是功能的集合,同样可看做是一种数据类型,是比抽象类更为抽象的”类”. 2. 接口中只允许出现抽象方法,不能出现非抽象方法 3. 接口的源文件也是java文件,编译后的文件也是. ...
- vue全家桶(3.1)
4.数据请求 4.1.axios是什么? axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,它有以下特征: 从浏览器中创建 XMLHttpRequest 从 no ...
- 【UVA11383】 Golden Tiger Claw 【二分图KM算法(板子)】
题目 题目传送门:https://www.luogu.com.cn/problem/UVA11383 分析 最近刚刚学了二分图,然后来了一个这样的题,看完题意之后,稍微想一想就能想出来是一个二分图,然 ...
- Vue父子之间的值传递
将通过两个input框实现父子之间的值传递作为演示,效果图 先注册父子各一个组件,代码如下 <div id="app"> <parent></pare ...
- Centos 下 Jenkins2.6 + Git + Maven Shell一件部署与备份
使用Jenkins2.6 集成Maven与Git插件做持续集成,同时编写Shell脚本备份与发布(需要稍微知道点Linux/毕竟基于Centos PS:本人Linux也是菜鸡) - 下载Jenkins ...
- 聊聊Java中的异常及处理
前言 在编程中异常报错是不可避免的.特别是在学习某个语言初期,看到异常报错就抓耳挠腮,常常开玩笑说编程1分钟,改bug1小时.今天就让我们来看看什么是异常和怎么合理的处理异常吧! 异常与error介绍 ...
- Dubbo 负载均衡的实现
前言 负载均衡是指在集群中,将多个数据请求分散在不同单元上进行执行,主要为了提高系统容错能力和加强系统对数据的处理能力. 在 Dubbo 中,一次服务的调用就是对所有实体域 Invoker 的一次筛选 ...
- MySQL CodeFirst的配置与注意事项
mysql+ef的配置相比较mssql+ef来说复杂一些.我的感受就是配置难度在于插件版本造成的各种不兼容问题.另外参考了很多博客,将多个博客里的经验综合才得以实现,因为不是每个人的操作都和那些博客作 ...
- day29 继承
目录 一.property装饰器 应用场景1 应用场景2 应用场景3(场景2优化) 二.继承介绍 1 语法 2 属性查找 3 继承的实现原理 3.1 菱形问题 3.2 继承原理 3.3 深度优先和广度 ...