昨天写了一些spring security的基本操作,今天来分享一下如何自定义自己的登录页面。
项目准备
基于昨天的项目,pom依赖不变,spring boot版本为2.1.7.RELEASE
org.springframework.boot
spring-boot-starter-security
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
开始
其实这块需求做起来没有多少工作量,但就是有一些spring security的机制可能大家不清楚就会一直被某些问题困扰。我们一个一个来解决一下。
实现自定义登录页面这个需求,我们需要做以下两件事情:
- 实现一个登录页面
- 配置spring security默认使用我们自己实现的登录页面
实现一个登陆页面
这里呢我就简单的写一个表单,大家根据自己的实际情况写自己的登录页面。
登录
这个页面命名为demo-login.html
,需要放在\src\main\resources\resources\
这个路径下(注意有两个resources文件夹)。放在这个路径下呢,项目启动起来之后可以直接访问到我们的html文件,这是spring boot默认配置。如果你不想放在这个文件夹下呢,就改一下spring boot的配置,具体怎么改呢网上很多,我就不再过多赘述了。
配置spring security
我们配置spring security需要写一个类,继承WebSecurityConfigurerAdapter
,然后根据自己的需求重写一些方法。我们自定义登录页面这个需求只需要重写void configure(HttpSecurity http)
这个方法即可。我们来写一下配置。
//不写这个注解配置不生效
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/demo-login.html")
.loginProcessingUrl("/demo-login");
}
}
上面写的配置很简单,我们大概解释一下。
第一行,表示spring security使用form表单登录的方式(另外还有一种登录的方式是Basic登录)
第二行,表示spring security默认的登录页路径为/demo-login.html
,就是我们上面写的html文件的名字
第三行,表示处理登录请求的接口为/demo-login
,就是我们上面写的form表单action
属性的值
写到这里我们启动一下项目试一下,看看是什么结果。
发现我们可以直接访问到接口,不需要登录。这是因为我们重写了void configure(HttpSecurity http)
这个方法,覆盖了spring security默认的访问控制的配置。我们来自己写一下这些配置。
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/demo-login.html")
.loginProcessingUrl("/demo-login")
.and()
.authorizeRequests()
.anyRequest().authenticated();
}
}
新加入了三行配置。就像字面意思上表示的一样,这三行配置表示所有的请求都需要认证。现在我们再来启动项目,访问一下接口。
这时候发现浏览器提示了重定向的次数过多
错误,这是为啥呢?我们来分析一下我们在浏览器地址栏里面输入我们接口地址按下回车之后都发生了啥。
访问/hello
接口,因为我们刚才配置了所有请求都需要身份认证,现在我们没有登录那自然就要跳转到登录页登录,跳转/demo-login.html
。可是/demo-login.html
也需要身份认证啊,那就再次跳转/demo-login.html
,这样重复往返就死循环下去了。
问题讲清楚之后,那解决方案就很明确了,把/demo-login.html
和/demo-login
(form表单action属性的值)配置为不需要认证,放行。
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/demo-login.html")
.loginProcessingUrl("/demo-login")
.and()
.authorizeRequests()
.antMatchers("/demo-login.html", "/demo-login").permitAll()
.anyRequest().authenticated();
}
}
加入一行配置,放行/demo-login.html
和/demo-login
。现在我们重启项目看一下。
现在就正常的显示了我们的登录页面,我们输入正确的用户名和密码尝试登录一下。
发现我们点击登录之后又回到了登录页面。查看网络请求,看到刚才那个登陆请求返回了302
状态码。查看Java的console之后也没有发现什么异常。我们尝试看一下debug日志,看看问题出在哪里。
改变spring boot的日志级别,添加配置logging.level.root=debug
,重启项目,重试刚才的操作,查看一下console。
我们发现报错了,显示无效的csrf token。这是因为spring security默认开启了csrf防护,只要在请求中带上csrf token就可以了。这个token在返回登录页面的时候spring security已经帮我们准备好了,只是我们没有使用模板引擎,所以取到token比较困难,这里我们把csrf关闭吧,大家可以自己摸索一下如何取到这个token,带上就完事了。重写一下配置。
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/demo-login.html")
.loginProcessingUrl("/demo-login")
.and()
.authorizeRequests()
.antMatchers("/demo-login.html", "/demo-login").permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable();
}
}
配置写到这就真的全部写完了。我们现在重启项目就可以登录访问接口了。
结语
需求实现了,总体来说没有太多的代码量。但是过程中会遇到很多问题,需要大家耐心的去发现。里面涉及到的一些技巧,像查看debug日志,就需要大家静下心来慢慢的查看问题出在哪里。通过自己独立思考解决问题也很过瘾。
话不多说,拜拜。