自定义登录界面采用了BootStrap官网例子,当然还不能直接使用,必须先修改页面的内容,再修改对应的控制器以及Spring Security
的配置。
引入Thymeleaf
和修改页面
把源码包下载回来,将其中的index.html
复制到新创建的resources\template\account
目录中,重新命名为login.html
,然后删除head
标签中的一些作者和其他信息,然后要开始使用Thymeleaf
了。
首先是在html
标签中引入Thymeleaf
的命名空间:
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
之后将下边这行:
<link href="../assets/dist/css/bootstrap.min.css" rel="stylesheet">
修改为:
<link href="/css/bootstrap.min.css" th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
这里尽量遵循Thymeleaf
的本意,就是不破坏原有页面结构。
下边那一行引入了signin.css
,我直接把signin.css
的内容复制到了head标签里,这样就只用这一个文件就可以了。
修改页面内容
首先是图标,需要显示原始的比例,所以去掉高和宽,改成公司的图标:
<img class="mb-4" src="/img/sinochem.png" th:src="@{/img/sinochem.png}" alt="中化集团" >
然后继续将英文Please sign in修改成“请登录”,之后修改两个input框的内容,由于Spring Security默认的表单键是username和password,修改如下:
<div class="form-floating">
<input type="text" class="form-control" id="floatingInput" placeholder="用户名" name="username">
<label for="floatingInput">用户名</label>
</div>
<div class="form-floating">
<input type="password" name="password" class="form-control" id="floatingPassword" placeholder="密码">
<label for="floatingPassword">密码</label>
</div>
接下来的复选框Remember Me
我不需要,就把这一部分删除。之后再修改好后边的登录按钮和版权信息。
修改表单POST
地址
这是一个非常重要的环节,刚才我们没有修改form
表单,form
表单需要将数据POST
到Spring Security
用于验证的地址,为了URL
的统一规范,我打算用户相关的超链接都用/account/
开头,所以准备把POST
地址设置为/account/auth
,修改如下:
<form action="/account/auth" th:action="@{/account/auth}" method="post">
配置控制器
由于Spring Security
可以指定自定义登录界面的URL,我打算设置为/account/login
,所以要为这个地址编写一个控制器。打算把所有/account/
开头的控制器都集中到一个类中,在cc.conyli.fms
下创建controller
包,然后创建AccountController
类:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/account")
public class AccountController {
@RequestMapping("/login")
public String login() {
return "/account/index";
}
}
修改Spring Security
配置
既然现在有了对应/account/login
路径的控制器,并且返回我们自己的页面,那么想到可以修改Spring Security
配置如下:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/account/login").permitAll();
}
就是添加了loginPage("/account/login")
,然后启动项目,随便访问路径,可以看到显示出了自定义的页面,然而问题是:没有样式
解决不显示样式的问题
页面没有样式的原因是,除了/account/login
这个路径之外,所有的路径都被Spring Security
保护起来,包括静态文件的路径,很显然,需要让Spring Security
放开这几个路径,于是继续修改配置:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/css/**","/img/**","/js/**","/webfonts/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/account/login").permitAll();
}
此时再刷新,就会发现样式显示正常了。
修改验证地址
目前输入用户名和密码发现没有用,这是因为表单里设置了POST
地址是/account/auth
,但是Spring Security
并没有设置这个POST
地址接受表单提交,需要继续修改:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/css/**","/img/**","/js/**","/webfonts/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/account/login").loginProcessingUrl("/account/auth").permitAll();
}
加了loginProcessingUrl("/account/auth")
,Spring Security
的过滤器就会在这个地址等着接收包含usermane
和password
的表单,然后返回登录是否成功的响应。
再重新运行项目,输入用户名和密码后,如果登录成功就会跳转到刚才想访问的路径,如果登录失败,则会返回http://localhost:8080/account/login?error
这样一个地址,既然登录失败,需要给用户一个提示,于是我们还需要对页面做一个处理,来提示登录失败。
修改控制器检查error
参数
控制器需要检查URL
参数error
是否存在,于是这里可以用到Spring
的@RequestParam(required = false)
来接受参数
@RequestMapping("/login")
public String login(@RequestParam(required = false, name = "error") String failed, Model model) {
//URL中的error参数存在,则在model中放入一个"failed"键,在页面中通过if来判断。
if (failed != null) {
model.addAttribute("failed", "用户名或密码错误,或用户未激活,请联系管理员");
}
return "/account/login";
}
使用th:if
在页面中进行判断
在页面中form
标签的h3
标题之后,加上一个alert
组件:
<div th:if="${failed} != null" class="alert alert-danger" role="alert">
用户名或密码错误,或用户未激活,请联系管理员。
</div>
当出现错误,控制器在模型中放入failed
之后,页面中就通过判断展示alert
组件。这样就写好了自定义的登录页面。