在本专栏前篇文章中介绍了HttpBasic模式,该模式比较简单,只是进行了通过携带Http的Header进行简单的登录验证,而且没有可以定制的登录页面,所以使用场景比较窄。
对于一个完整的应用系统,与登录验证相关的页面都是高度定制化的,非常美观而且提供多种登录方式。这就需要Spring Security支持我们自己定制登录页面,也就是本文给大家介绍的FormLogin模式登录认证模式。
1. 新建项目
在介绍相关内容之前,需要先搭建一个demo,新建一个项目spring-security-02,需要添加依赖如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
除此之外其实还需要添加web、thymeleaf的依赖,这里就不在贴出来了。
demo结构如下:
2. 新建登录页面
这里不再使用Security默认的页面,自己定制一个,代码如下:
单纯的一个表单登录页面,需要注意以下几个参数:
- action:security登录的url,可以自定义。
- username:security登录的用户名,可以自定义。
- password:security登录的密码,可以自定义。
以上三个参数都可以在security通过配置的方式定义。
3. 新建首页
这个是登录成功后跳转的首页,代码如下:
4. 新建接口
在security中一切的接口都称之为资源,下面新建两个测试接口,代码如下:
5. formLogin配置
在介绍如何配置之前,先来看下formLogin模式登录的5个要素:
- 登录认证逻辑-登录URL:这个URL在security中默认是/login且POST请求,但是也可以通过配置自定义。
- 如何接收登录参数:用户名、密码默认接收的字段分别是username、password,同样也是可以通过配置自定义。
- 登陆成功后逻辑:登录成功后的处理逻辑,比如跳转到指定的页面、返回特定的JSON数据,这个也是可以定制。
- 资源访问控制规则:这个用于控制什么用户、什么角色可以访问什么资源,可以静态指定也可以从数据库中加载。
- 用户具有角色权限:配置某个用户拥有什么角色、拥有什么权限,可以静态指定也可以从数据库中加载。
一般来说,使用权限认证框架的的业务系统登录验证逻辑是固定的,而资源访问控制规则和用户信息是从数据库或其他存储介质灵活加载的。但本文所有的用户、资源、权限信息都是代码配置写死的,旨在为大家介绍formLogin认证模式,如何从数据库加载权限认证相关信息我还会结合RBAC权限模型再写文章的。
针对上述5个的要素,formLogin配置代码如下:
首先,我们要继承WebSecurityConfigurerAdapter ,重写configure(HttpSecurity http) 方法,该方法用来配置登录验证逻辑。请注意看代码中的注释信息。
上述代码分为两个部分:
第一部分是formLogin配置段,用于配置登录验证逻辑相关的信息。如:登录页面、登录成功页面、登录请求处理路径等。
- .loginPage("/login/page"):指定的第2步定制的登录页面,需要写个mvc接口跳转到login.html,见源码。
- .loginProcessingUrl("/login"):指定处理登录的逻辑的url,这个接口不需要开发者定义,security中通过过滤器。UsernamePasswordAuthenticationFilter处理,后文介绍。
- .usernameParameter("username"):指定用户名的接收参数的字段,默认是username,具体逻辑在UsernamePasswordAuthenticationFilter。
- .passwordParameter("password"):指定密码的接收参数的字段,默认是username,具体逻辑在UsernamePasswordAuthenticationFilter。
- .defaultSuccessUrl("/"):登录认证成功后默认转跳的路径,这里/则是跳转到/index.html,可以自定义。
- .failureUrl("/login/page"):登陆失败的跳转的路径。
第二部分是authorizeRequests配置段,用于配置资源的访问控制规则
- .antMatchers("/login/page","/login").permitAll():配置登录页面、登录接口直接放行,不需要拦截登录
- .antMatchers("/","/hello1").hasAnyAuthority("ROLE_user","ROLE_admin"):设置/hello1、/这两个资源需要user和admin的角色才可以访问。
- .antMatchers("/hello2").hasAnyRole("admin"):配置/hello2这个资源需要admin的角色才可以访问。
- .anyRequest().authenticated():除了上面的配置的规则,访问其他的资源都需要登录认证通过才可以访问。
6. 用户、角色配置
在上述的规则中配置了一些资源需要特定的角色才可以访问,比如user、admin,那么这些角色如何去指定呢?
在security中提供了配置的方式,代码如下:
上述的代码配置很简单,创建了两个用户且指定了角色,分别如下:
- user:密码123456,赋予的角色为user。
- admin:密码123456,赋予的角色为user、admin。
配置解释如下:
- .inMemoryAuthentication():指的是在内存里面存储用户的身份认证和授权信息;这里还可以配置从数据库中动态加载,后文介绍。
- withUser("user"):用户名是user。
- password(passwordEncoder().encode("123456")):密码是加密之后的123456。
- roles():方法用于指定用户的角色,一个用户可以有多个角色。
- passwordEncoder(passwordEncoder()):指定密码的加密方式,使用的是BCryptPasswordEncoder,后文介绍。
7. 简单测试
按照上述6个步骤基本实现了一个表单登录,下面测试一下。
浏览器访问http://localhost:8081/hello2,第一次访问由于未登录会自动跳转到登录页面,如下图:
输入用户名和密码,由于/hello2这个资源需要admin的角色才能访问,因此必须用admin这个用户登录,否则将会报403的错误,登录成功后将能够正常访问。
如果用户名或者密码错误将会触发.failureUrl("/login/page")这个配置,自动跳转到登录页面
8. 自定义登录结果
在第5步的配置中,和登录结果相关的配置有如下两个:
- .defaultSuccessUrl("/"):登录认证成功后默认转跳的路径,这里/则是跳转到/index.html,可以自定义。
- .failureUrl("/login/page"):登陆失败的跳转的路径。
这两个配置都是指定URL的方式:
- 当我们登录成功的时候,是由AuthenticationSuccessHandler进行登录结果处理,默认跳转到defaultSuccessUrl配置的路径对应的资源页面(一般是首页index.html)。
- 当我们登录失败的时候,是由AuthenticationfailureHandler进行登录结果处理,默认跳转到failureUrl配置的路径对应的资源页面(一般也是跳转登录页login.html,重新登录)。
但是在web应用开发过程中需求是千变万化的,有时需要我们针对登录结果做个性化处理,比如:
- 我们希望不同的人登陆之后,看到不同的首页(及向不同的路径跳转)。
- 我们应用是前后端分离的,验证响应结果是JSON格式数据,而不是页面跳转。
- …… 其他未尽的例子。
因此需要自定义的登录结果,这篇文章先介绍如何定制跳转页面,关于JSON格式数据就是前后端分离架构下需要用到。
8.1 自定义登录成功结果
AuthenticationSuccessHandler接口是Security提供的认证成功处理器接口,我们只需要去实现它即可。但是通常来说,我们不会直接去实现AuthenticationSuccessHandler接口,而是继承SavedRequestAwareAuthenticationSuccessHandler 类,这个类会记住用户上一次请求的资源路径,比如/hello2这个路径,登录成功后将会自动跳转到/hello2这个页面而不是首页。
代码如下:
8.2 自定义登录失败结果
这里我们同样没有直接实现AuthenticationFailureHandler接口,而是继承SimpleUrlAuthenticationFailureHandler 类。该类中默认实现了登录验证失败的跳转逻辑,即登陆失败之后回到登录页面。我们可以利用这一点简化我们的代码。
代码如下:
8.3 SecurityConfig中配置
配置如下:
将自定义的AuthenticationSuccessHandler和AuthenticationFailureHandler注入到Spring Security配置类中
使用formlogin模式,配置successHandler和failureHandler。
不要配置defaultSuccessUrl和failureUrl,否则自定义handler将失效。handler配置与URL配置只能二选一
总结
本篇文章介绍了Spring Security 的 formLogin的配置方式,需要注意的是这里不支持前后端分离架构,