自定义用户登录
通过前面几个示例演示可以发现,项目中并没有配置用户登录页面和登录处理方法,但是演示过程中却提供了一个默认的用户登录页面,并且进行了自动登录处理,这就是Spring Security提供的默认登录处理机制。实际开发中,通常要求定制更美观的用户登录页面,并配置有更好的错误提示信息,此时需要自定义用户登录控制。下面,围绕formLogin()这个方法来探索并讲解自定义用户登录的具体实现。
formLogin()用户登录方法涉及到用户登录的主要方法及说明如表1所示。
表1 用户登录相关的主要方法及说明
方法 | 描述 |
---|---|
loginPage(String loginPage) | 用户登录页面跳转路径,默认为get请求的/login |
successForwardUrl(String forwardUrl) | 用户登录成功后的重定向地址 |
successHandler(AuthenticationSuccessHandler successHandler) | 用户登录成功后的处理 |
defaultSuccessUrl(String defaultSuccessUrl) | 用户直接登录后默认跳转地址 |
failureForwardUrl(String forwardUrl) | 用户登录失败后的重定向地址 |
failureUrl(String authenticationFailureUrl) | 用户登录失败后的跳转地址,默认为/login?error |
failureHandler(AuthenticationFailureHandler authenticationFailureHandler) | 用户登录失败后的错误处理 |
usernameParameter(String usernameParameter) | 登录用户的用户名参数,默认为username |
passwordParameter(String passwordParameter) | 登录用户的密码参数,默认为password |
loginProcessingUrl(String loginProcessingUrl) | 登录表单提交的路径,默认为post请求的/login |
permitAll() | 无条件对请求进行放行 |
了解了Spring Security中关于用户登录的相关方法后,下面,在前一个自定义用户访问控制案例的基础上实现自定义用户登录功能。
1.自定义用户登录页面
要实现自定义用户登录功能,首先必须根据需要自定义一个用户登录页面。在项目的resources/ templates目录下新创建一个名为login的文件夹(专门处理用户登录),在该文件夹中创建一个用户登录页面login.html,内容如文件1所示。
文件1 login.html
1 <!DOCTYPE html>
2 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5 <title>用户登录界面</title>
6 <link th:href="@{/login/css/bootstrap.min.css}" rel="stylesheet">
7 <link th:href="@{/login/css/signin.css}" rel="stylesheet">
8 </head>
9 <body class="text-center">
10 <form class="form-signin" th:action="@{/userLogin}" th:method="post" >
11 <img class="mb-4" th:src="@{/login/img/login.jpg}" width="72px" height="72px">
12 <h1 class="h3 mb-3 font-weight-normal">请登录</h1>
13 <!-- 用户登录错误信息提示框 -->
14 <div th:if="${param.error}"
15 style="color: red;height: 40px;text-align: left;font-size: 1.1em">
16 <img th:src="@{/login/img/loginError.jpg}" width="20px">用户名或密码错误,请重新登录!
17 </div>
18 <input type="text" name="name" class="form-control"
19 placeholder="用户名" required="" autofocus="">
20 <input type="password" name="pwd" class="form-control"
21 placeholder="密码" required="">
22 <button class="btn btn-lg btn-primary btn-block" type="submit" >登录</button>
23 <p class="mt-5 mb-3 text-muted">Copyright© 2019-2020</p>
24 </form>
25 </body>
26 </html>
文件1中,通过<form>标签定义了一个用户登录功能,且登录数据以POST方式向“/userLogin”路径进行提交。其中,登录表单中的用户名参数和密码参数可以自行定义;登录数据提交方式必须为post,提交的路径也可以自行定义。同时,在第14~17行代码中有一个专门用来存储登录错误后返回错误信息的<div>块,在该<div>块中使用th:if="${param.error}"来判断请求中是否带有一个error参数,从而判断是否登录成功,该参数是Security默认的,用户可以自行定义。
文件1中还引入了两个CSS样式文件和两个IMG图片文件,用来渲染用户登录页面,它们都存在于/login/**目录下,需要提前引入这些静态资源文件到chapter07项目resources下的static目录中。引入这些静态资源文件后,结构如图1所示。
图1引入登录页面静态资源效果
2.自定义用户登录跳转
在之前创建的FilmeController类中添加一个跳转到登录页面login.html的方法,示例代码如下。
@GetMapping("/userLogin")
public String toLoginPage() {
return "login/login";
}
在上述添加的toLoginPage()方法中,配置了请求路径为“/userLogin”的Get请求,并向静态资源根目录下的login文件夹下的login.html页面跳转。
需要说明的是,Spring Security默认使用Get方式的“/login”请求用于向登录页面跳转,默认使用Post方式的“/login”请求用于对登录后的数据进行处理。因此,自定义用户登录控制时,需要提供向用户登录页面跳转的方法,且自定义的登录页跳转路径必须与数据处理提交路径一致。例如示例中,“/userLogin”的Get请求向登录页跳转,则必须使用路径为“/userLogin”的Post请求进行登录数据处理。
3.自定义用户登录控制
完成上面的准备工作后,打开SecurityConfig类,重写configure(HttpSecurity http)方法实现用户登录控制,示例代码如下。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll()
// 需要对static文件夹下静态资源进行统一放行
.antMatchers("/login/**").permitAll()
.antMatchers("/detail/common/**").hasRole("common")
.antMatchers("/detail/vip/**").hasRole("vip")
.anyRequest().authenticated();
// 自定义用户登录控制
http.formLogin()
.loginPage("/userLogin").permitAll()
.usernameParameter("name").passwordParameter("pwd")
.defaultSuccessUrl("/")
.failureUrl("/userLogin?error");
}
上述代码中,在上一小节示例的基础上添加了通过formLogin()的相关方法进行自定义用户登录功能的实现,同时在原有的请求控制方法authorizeRequests()中添加了对static文件夹下静态资源的统一放行处理。下面,对上述示例中用户登录控制的相关方法和静态资源放行方法进行说明,具体如下。
● loginPage("/userLogin")方法指定了向自定义登录页跳转的请求路径(前面定义的toLoginPage()方法的请求映射路径),并使用permitAll()方法对进行登录跳转的请求进行放行;
● usernameParameter("name")和passwordParameter("pwd")方法来接收登录时提交的用户名和密码。这里的参数name和pwd必须和login.html中用户名、密码中的name属性值保持一致,如果login.html中的name属性值是默认的username和password,这两个方法就可以省略;
● defaultSuccessUrl("/")方法指定了用户登录成功后默认跳转到项目首页;
● failureUrl("/userLogin?error")方法用来控制用户登录认证失败后的跳转路径,该方法默认参数为“/login?error”。其中,参数中的“/userLogin”为向登录页面跳转的映射,error是一个错误标识,作用是登录失败后在登录页面进行接收判断,例如login.html示例中的${param.error},这两者必须保持一致;
● antMatchers("/login/**").permitAll()方法的作用是对项目static文件夹下login包及其子包中的静态资源文件进行统一放行处理。如果没有对静态资源放行,未登录的用户访问项目首页时就无法加载页面关联的静态资源文件。
4.效果测试
重启chapter07项目进行效果测试,项目启动成功后,通过浏览器访问“http:``//localhost:8080/”会直接进入到项目首页。在项目首页,单击普通电影或者VIP专享电影名称查询电影详情,效果如图1所示。
图1 访问影片详情效果
再次访问影片详情时,已经被Security拦截并跳转到自定义的用户登录页面login.html。此登录界面输入错误的账号信息后,效果如图2所示。
图2 用户登录失败效果
从图2可以看出,如果在自定义的登录页面中输入错误用户信息,会返回到了当前登录页面,此时的请求路径上已经携带了error错误标识,并且登录页面也有错误信息提示,说明自定义登录失败设置成功。
使用正确的账户进行登录,并查看影片详情页面,访问效果与之前的成功案例一样,读者可以自行演示查看。