- 2023-09-28 12:11:57
- 980 热度
- 0 评论
流程做微人事的小伙伴(https://github.com/lenve/vhr),应该都发现了在微人事中有一个极为特殊的请求,那就是登录。
登录请求是一个 POST 请求,但是数据传输格式是 key/value 的形式。整个项目里就只有这一个 POST 请求是这样,其他 POST 请求都是 JSON 格式的数据。
为什么做成这个样子呢?还是懒呗。
因为 Spring Security 中默认的登录数据格式就是 key/value 的形式,一直以来懒得改。最近刚好在录 Spring Security,就抽空把这里调整了下,这样前后端就能统一起来了。
好了,我们一起来看下怎么实现。
1.服务端接口调整
首先大家知道,用户登录的用户名/密码是在 UsernamePasswordAuthenticationFilter
类中处理的,具体的处理代码如下:
1 |
public Authentication attemptAuthentication(HttpServletRequest request, |
从这段代码中,我们就可以看出来为什么 Spring Security 默认是通过 key/value 的形式来传递登录参数,因为它处理的方式就是 request.getParameter。
所以我们要定义成 JSON 的,思路很简单,就是自定义来定义一个过滤器代替 UsernamePasswordAuthenticationFilter
,然后在获取参数的时候,换一种方式就行了。
这里有一个额外的点需要注意,就是我们的微人事现在还有验证码的功能,所以如果自定义过滤器,要连同验证码一起处理掉。
2.自定义过滤器
接下来我们来自定义一个过滤器代替 UsernamePasswordAuthenticationFilter
,如下:
1 |
public class LoginFilter extends UsernamePasswordAuthenticationFilter { |
这段逻辑我们基本上是模仿官方提供的 UsernamePasswordAuthenticationFilter
来写的,我来给大家稍微解释下:
- 首先登录请求肯定是 POST,如果不是 POST ,直接抛出异常,后面的也不处理了。
- 因为要在这里处理验证码,所以第二步从 session 中把已经下发过的验证码的值拿出来。
- 接下来通过 contentType 来判断当前请求是否通过 JSON 来传递参数,如果是通过 JSON 传递参数,则按照 JSON 的方式解析,如果不是,则调用 super.attemptAuthentication 方法,进入父类的处理逻辑中,也就是说,我们自定义的这个类,既支持 JSON 形式传递参数,也支持 key/value 形式传递参数。
- 如果是 JSON 形式的数据,我们就通过读取 request 中的 I/O 流,将 JSON 映射到一个 Map 上。
- 从 Map 中取出 code,先去判断验证码是否正确,如果验证码有错,则直接抛出异常。验证码的判断逻辑,大家可以参考:無名手把手教你给微人事添加登录验证码。
- 接下来从 Map 中取出 username 和 password,构造 UsernamePasswordAuthenticationToken 对象并作校验。
过滤器定义完成后,接下来用我们自定义的过滤器代替默认的 UsernamePasswordAuthenticationFilter
,首先我们需要提供一个 LoginFilter 的实例:
1 |
@Bean |
当我们代替了 UsernamePasswordAuthenticationFilter
之后,原本在 SecurityConfig#configure 方法中关于 form 表单的配置就会失效,那些失效的属性,都可以在配置 LoginFilter 实例的时候配置。
另外记得配置一个 AuthenticationManager,根据 WebSecurityConfigurerAdapter 中提供的配置即可。
FilterProcessUrl 则可以根据实际情况配置,如果不配置,默认的就是 /login
。
最后,我们用自定义的 LoginFilter 实例代替 UsernamePasswordAuthenticationFilter
,如下:
1 |
@Override |
调用 addFilterAt 方法完成替换操作。
篇幅原因,我这里只展示了部分代码,完整代码小伙伴们可以在 GitHub 上看到:https://github.com/lenve/vhr。
配置完成后,重启后端,先用 POSTMAN 测试登录接口,如下:
3.前端修改
原本我们的前端登录代码是这样的:
1 |
this.$refs.loginForm.validate((valid) => { |
首先我们去校验数据,在校验成功之后,通过 postKeyValueRequest 方法来发送登录请求,这个方法是我自己封装的通过 key/value 形式传递参数的 POST 请求,如下:
1 |
export const postKeyValueRequest = (url, params) => { |
postKeyValueRequest 是我封装的通过 key/value 形式传递参数,postRequest 则是通过 JSON 形式传递参数。
所以,前端我们只需要对登录请求稍作调整,如下:
1 |
this.$refs.loginForm.validate((valid) => { |
配置完成后,再去登录,浏览器按 F12 ,就可以看到登录请求的参数形式了:
好啦,这就是無名和大家介绍的 SpringSecurity+JSON+验证码登录,如果觉得还不错,记得点一下右下角在看哦。
完整代码小伙伴们可以在 GitHub 上下载:https://github.com/lenve/vhr
- Spring(403)
- Boot(208)
- Spring Boot(187)
- Java(82)
- Cloud(82)
- Spring Cloud(82)
- Security(60)
- Spring Security(54)
- Boot2(51)
- Spring Boot2(51)
- Redis(31)
- SQL(29)
- Mysql(25)
- IDE(24)
- Dalston(24)
- JDBC(22)
- IDEA(22)
- mongoDB(22)
- MVC(22)
- Web(21)
- CLI(20)
- Alibaba(19)
- SpringMVC(19)
- SpringBoot(17)
- Docker(17)
- Eclipse(16)
- Vue(16)
- Git(16)
- JPA(15)
- Apache(15)
- ORA(15)
- Oracle(14)
- jdk(14)
- Tomcat(14)
- Linux(14)
- HTTP(14)
- Mybatis(14)
- XML(13)
- JdbcTemplate(13)
- OAuth(13)
- Nacos(13)
- Pro(13)
- JSON(12)
- OAuth2(12)
- Data(12)
- stream(11)
- int(11)
- Myeclipse(11)
- not(10)
- Bug(10)
- maven(9)
- Map(9)
- Hystrix(9)
- ast(9)
- APP(8)
- Bit(8)
- API(8)
- session(8)
- Window(8)
- Swagger(8)
- JavaMail(7)
- Cache(7)
- File(7)
- IntelliJ(7)
- mail(7)
- windows(7)
- too(7)
- HTML(7)
- Github(7)
- Excel(6)
- Log4J(6)
- pushlet(6)
- apt(6)
- read(6)
- Freemarker(6)
- WebFlux(6)
- JSP(6)
- Bean(6)
- error(6)
- Server(6)
- nginx(6)
- ueditor(6)
- jar(6)
- ehcache(6)
- UDP(6)
- RabbitMQ(6)
- star(6)
- and(6)
- Struts(5)
- string(5)
- script(5)
- Syntaxhighlighter(5)
- Tool(5)
- Controller(5)
- swagger2(5)
- ldquo(5)
- input(5)
- Servlet(5)
- Config(5)
- discuz(5)