Spring Security系列教程05--实现Form表单认证

简介: 前言在上一章节中,一一哥 带大家认识了Spring Security中的第一种认证方式,但是这种基本认证的方式,UI效果不漂亮,安全性也很差,好像一无是处的样子,那么有没有更好一点的认证方式呢?有的!接下来我给大家介绍一个新的认证方式,即Form表单认证。一. Form表单认证1. 认证方式我们从前文中得知,Spring Security中的认证方式可以分为HTTP层面和表单层面,常见的认证方式如下:• ①. HTTP基本认证;• ②. Form表单认证;• ③. HTTP摘要认证;

前言

在上一章节中,一一哥 带大家认识了Spring Security中的第一种认证方式,但是这种基本认证的方式,UI效果不漂亮,安全性也很差,好像一无是处的样子,那么有没有更好一点的认证方式呢?有的!接下来我给大家介绍一个新的认证方式,即Form表单认证。

一. Form表单认证

1. 认证方式

我们从前文中得知,Spring Security中的认证方式可以分为HTTP层面和表单层面,常见的认证方式如下:

  • ①. HTTP基本认证;
  • ②. Form表单认证;
  • ③. HTTP摘要认证;

2. 表单认证简介

对于表单认证,其实在SpringBoot开发环境中,只要我们添加了Spring Security的依赖包,就会自动实现表单认证。是这样的吗? 我们来看看源码吧,在WebSecurityConfigurerAdapter类的config(HttpSecurity http)方法中,可以看到如下默认实现。

所以在SpringBoot环境中,默认支持的就是表单认证方式。

3. 表单认证效果

各位回想一下,我们在之前的章节中,创建的第一个Spring Security项目中实现的效果,其实就是表单认证。每次我们在访问某个Web接口之前,都会重定向到一个Security自带的login登录页面上,这个登录页面,就是表单认证的效果。

4. 表单认证中的预置url和页面

这时候有的小伙伴可能就会很好奇,为什么表单认证会有以上效果?这是因为在默认的formLogin配置中,自动配置了一些url和页面:

  • /login(get): get请求时会跳转到这个页面,只要我们访问任意一个需要认证的请求时,都会跳转到这个登录界面。
  • /login(post): post请求时会触发这个接口,在登录页面点击登录时,默认的登录页面表单中的action就是关联这个login接口。
  • /login?error: 当用户名或密码错误时,会跳转到该页面。
  • /: 登录成功后,默认跳转到该页面,如果配置了index.html页面,则 ”/“ 会重定向到index.html页面,当然这个页面要由我们自己实现。
  • /logout: 注销页面。
  • /login?logout: 注销成功后跳转到的页面。

由此可见,SpringSecurity默认有两个login,即登录页面和登录接口的地址都是 /login:

如果是 GET 请求,表示你想访问登录页面;如果是 POST 请求,表示你想提交登录数据。

对于这几个URL接口,我们简单了解即可。

二. 自定义表单认证配置

在第一节中,我们只是了解了Spring Security内部是如何实现默认的表单认证的,那么我们如何自定义表单认证配置呢?

接下来 一一哥 带各位创建一个新的model,讲解如何实现自定义表单认证,项目的具体创建过程略,请参考《Spring Security系列教程03--创建SpringSecurity项目》。

1. 创建SecurityConfig配置类

我们先编写一个类,继承自WebSecurityConfigurerAdapter父类,该类的作用如下:

  • 验证所有请求;
  • 允许用户使用表达登录进行身份验证;
  • 允许用户使用Http基本认证。

代码如下:

packagecom.yyg.security.config;
importorg.springframework.security.config.annotation.web.builders.HttpSecurity;
importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/*** @Author: 一一哥* @Blame: yyg* @Since: Created in 2021/4/14*/@EnableWebSecuritypublicclassSecurityConfigextendsWebSecurityConfigurerAdapter {
@Overrideprotectedvoidconfigure(HttpSecurityhttp) throwsException {
//super.configure(http);//配置表单认证方式http.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
//开启表单认证                .formLogin();
    }
}

我们在SecurityConfig类上添加@EnableWebSecurity注解后,会自动被Spring发现并注册。在configure()方法中,我执行了formLogin()方法,该方法的功能就是开启表单认证。

2. 代码结构

我们看看现在的代码结构,跟上一篇文章的代码结构其实是一样的,小伙伴们可以直接在你上一个案例基础之上直接修改,我这里为了方便大家查看,所以有新建了一个新的model。

3. 启动项目

接下来启动项目,访问我们定义的/hello接口时,首先会重定向到/login页面。

我们只有输入自己配置的用户名和密码后,才可以正常访问/hello接口。

当认证成功后,内部再次发生了302重定向:

可见从/login接口重定向到了/hello接口。这样我们通过几行代码,就实现了自定义的表单认证,是不是也很简单?简单就对了,其实我们开发时用到的各种框架,使用起来都并不难,主要是掌握其用法和内部原理即可。

三. 自定义表单认证的登录界面

但是有的小伙伴可能会说,这个默认提供的表单登录页面看起来有点丑,或者与我们项目中其他页面的UI风格并不一致,能不能自定义这个登录页面呢?

一一哥 在第一章节中给大家介绍Spring Security时就说过,它的一个特点就在于可以高度自定义,灵活配置,所以我们当然可以自定义一个登录页面。

1. 服务端代码定义

如果想实现自定义登录页面,我们可以在上面定义的SecurityConfig 类中,复写configure(WebSecurity web) 和 configure(HttpSecurity http) 方法,通过loginPage()方法来配置自定义登录页面,代码如下:

packagecom.yyg.security.config;
importorg.springframework.security.config.annotation.web.builders.HttpSecurity;
importorg.springframework.security.config.annotation.web.builders.WebSecurity;
importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/*** @Author: 一一哥* @Blame: yyg* @Since: Created in 2021/4/14*/@EnableWebSecuritypublicclassSecurityConfigextendsWebSecurityConfigurerAdapter {
/*** 用来定义哪些请求需要忽略安全控制,哪些请求必须接受安全控制;还可以在合适的时候清除SecurityContext以避免内存泄漏,* 同时也可以用来定义请求防火墙和请求拒绝处理器,另外我们开启Spring Security Debug模式也是这里配置的*/@Overridepublicvoidconfigure(WebSecurityweb) throwsException {
//super.configure(web);web.ignoring()
                .antMatchers("/js/**", "/css/**", "/images/**");
    }
@Overrideprotectedvoidconfigure(HttpSecurityhttp) throwsException {
//super.configure(http);//2.配置自定义的登录页面http.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .formLogin()
//加载自定义的登录页面地址                .loginPage("/myLogin.html")
                .permitAll()
                .and()
//注意:需禁用crsf防护功能,否则登录不成功                .csrf()
                .disable();
    }
}

以上这段代码,就是实现自定义登录页面的核心代码了。

你会发现实现自定义表单认证的代码很简单,但是Spring Security内部是如何加载我们自定义的登录页面的呢?有哪些类或方法来负责完成呢?如果想要弄明白这个原理,我们需要先了解2个核心参数:WebSecurity和HttpSecurity,接下来我带各位分别了解一下这2个核心参数。

1.1 WebSecurity执行流程

我们先看下图:

这是我们请求时,WebSecurity的执行流程图。

configure(WebSecurity web)方法中,有个核心参数:WebSecurity类!在这个类里定义了一个securityFilterChainBuilders集合,可以同时管理多个SecurityFilterChain过滤器链,各位可以回顾我们学习Web基础时,关于过滤器的知识点,这些过滤器的执行是不是比Servlet更早?

当WebSecurity在执行时,会构建出一个名为 ”springSecurityFilterChain“Spring BeanFilterChainProxy代理类,它的作用是来 定义哪些请求可以忽略安全控制,哪些请求必须接受安全控制以及在合适的时候 清除SecurityContext 以避免内存泄漏,同时也可以用来 定义请求防火墙和请求拒绝处理器,也可以在这里 开启Spring Security 的Debug模式

因为有上面这一系列的Filter过滤器,我们就可以利用web.ignoring() 方法来配置想要忽略的静态资源 URL 地址,这样这些静态资源就可以不被拦截,从而可以被识别访问了。

1.2 HttpSecurity作用

了解完了WebSecurity的作用之后,一一哥 再带各位学习一下HttpSecurity的作用。

HttpSecurity用来构建包含一系列的过滤器链SecurityFilterChain,平常我们的配置就是围绕着这个SecurityFilterChain进行。

2. 页面定义

了解完内部执行原理,接下来我们进行代码实现,首先自定义一个登陆页面,主要是编写html代码和css样式,各位小伙伴可以发挥你们的前端能力,编写自己满意的登录页面吧,其核心代码如下:

<body><divclass="login"><h2>Access Form</h2><divclass="login-top"><h1>登录验证</h1><formaction="/myLogin.html"method="post"><inputtype="text"name="username"placeholder="username"/><inputtype="password"name="password"placeholder="password"/><divclass="forgot"><ahref="#">忘记密码</a><inputtype="submit"value="登录"></div></form></div><divclass="login-bottom"><h3>新用户&nbsp;<ahref="#">&nbsp;</a></h3></div></div></body>

注意:

form表单中action的值,请暂时先写成”/myLogin.html“。

3. 代码结构

此时我们项目的包结构如下图所示:

4. 启动项目

启动项目后,我们访问接口时,就会自动跳转到自己定义的/myLogin.html页面上,输入用户名和密码后,就可以成功访问自己的接口。

这时候小伙伴会发现,我们的登录页面比之前默认的登录页面漂亮多了,赞一个呗!

四. 细化表单认证配置

在上面的章节中,我们实现了自定义的表单认证登录页面,但是有些小伙伴可能觉得以上的案例,并不够灵活,尤其是一些关于表单的参数,能不能自定义呢?一一哥 可以负责的告诉你,完全没问题!所以我们进一步细化表单认证的配置,以满足我们更多的需求。

比如我们现在想修改表单认证页面中请求参数的名称,定义认证失败时的错误处理页面,处理退出登录时的操作等,这些都可以自定义配置,实现代码如下。

1. 定义SecurityConfig类

packagecom.yyg.security.config;
importorg.springframework.security.config.annotation.web.builders.HttpSecurity;
importorg.springframework.security.config.annotation.web.builders.WebSecurity;
importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/*** @Author: 一一哥* @Blame: yyg* @Since: Created in 2021/4/14*/@EnableWebSecuritypublicclassSecurityConfigextendsWebSecurityConfigurerAdapter {
/*** 用来定义哪些请求需要忽略安全控制,哪些请求必须接受安全控制;还可以在合适的时候清除SecurityContext以避免内存泄漏,* 同时也可以用来定义请求防火墙和请求拒绝处理器,另外我们开启Spring Security Debug模式也是这里配置的*/@Overridepublicvoidconfigure(WebSecurityweb) throwsException {
//super.configure(web);web.ignoring()
                .antMatchers("/js/**", "/css/**", "/images/**");
    }
@Overrideprotectedvoidconfigure(HttpSecurityhttp) throwsException {
//super.configure(http);//3.进一步配置自定义的登录页面   //拦截请求,创建FilterSecurityInterceptor http.authorizeRequests() 
                .anyRequest()
                .authenticated()
//用and来表示配置过滤器结束,以便进行下一个过滤器的创建和配置                .and() 
//设置表单登录,创建UsernamePasswordAuthenticationFilter                .formLogin()                    
                .loginPage("/myLogin.html")
                .permitAll()
//指登录成功后,是否始终跳转到登录成功url。它默认为false                .defaultSuccessUrl("/index.html",true)
//post登录接口,登录验证由系统实现                .loginProcessingUrl("/login")
//用户密码错误跳转接口                .failureUrl("/error.html")
//要认证的用户参数名,默认username                .usernameParameter("username")
//要认证的密码参数名,默认password                .passwordParameter("password")
                .and()
//配置注销                .logout()
//注销接口                .logoutUrl("/logout")
//注销成功后跳转到的接口                .logoutSuccessUrl("/myLogin.html")
                .permitAll()
//删除自定义的cookie                .deleteCookies("myCookie")
                .and()
//注意:需禁用crsf防护功能,否则登录不成功                .csrf()
                .disable();
    }
}

2. 自定义登录页面

这时候我们把登录页面也跟着修改一下,主要是把form表单中action的值修改掉。

<body><divclass="login"><h2>Access Form</h2><divclass="login-top"><h1>登录验证</h1><formaction="/login"method="post"><inputtype="text"name="username"placeholder="username"/><inputtype="password"name="password"placeholder="password"/><divclass="forgot"><ahref="#">忘记密码</a><inputtype="submit"value="登录"></div></form></div><divclass="login-bottom"><h3>新用户&nbsp;<ahref="#">&nbsp;</a></h3></div></div></body>

注意:

此时form表单中action的值,要写成”/login“,因为我们在配置类中通过“loginProcessingUrl("/login")”方法中做了明确的配置。

3. 定义错误处理页面

小伙伴又提问了,当我们输入了错误的用户名和密码后,这时候会怎么办呢?其实这里我们可以提供一个错误处理页面,当认证失败后跳转到这个页面即可。我们这里简单实现一下,另外index.html页面与该页面类似,就是简单模拟。

4. 代码结构

此时项目的包结构如下图所示,各位可以参考:

4. 启动项目测试

这时候我们如果访问自己的接口,比如/hello,会先重定向到/myLogin.html页面,输入自己配置的用户名和密码,经过验证后,才会重定向到/index.html页面中,否则会重定向到我们配置的/error.html页面中。

4.1 重定向到/myLogin.html

访问资源时,会先重定向到自定义的登录页面。

4.2 重定向到/index.html

认证成功后,会重定向到index.html页面。

4.3 重定向到/error.html

认证失败后,会重定向到自定义的错误处理页面。

通过本案例,各位会发现,Spring Security的配置是很灵活的,当然这只是我们学习的开端,后面还有更多内容要学习,坚持往下看哦!有什么问题请各位在评论区留言......

相关文章
|
10月前
|
JSON 安全 Java
什么是JWT?如何使用Spring Boot Security实现它?
什么是JWT?如何使用Spring Boot Security实现它?
1761 5
|
2月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
375 3
|
18天前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
212 4
|
7月前
|
安全 Java Apache
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 身份和权限认证
本文介绍了 Apache Shiro 的身份认证与权限认证机制。在身份认证部分,分析了 Shiro 的认证流程,包括应用程序调用 `Subject.login(token)` 方法、SecurityManager 接管认证以及通过 Realm 进行具体的安全验证。权限认证部分阐述了权限(permission)、角色(role)和用户(user)三者的关系,其中用户可拥有多个角色,角色则对应不同的权限组合,例如普通用户仅能查看或添加信息,而管理员可执行所有操作。
331 0
|
3月前
|
Java Linux 网络安全
Linux云端服务器上部署Spring Boot应用的教程。
此流程涉及Linux命令行操作、系统服务管理及网络安全知识,需要管理员权限以进行配置和服务管理。务必在一个测试环境中验证所有步骤,确保一切配置正确无误后,再将应用部署到生产环境中。也可以使用如Ansible、Chef等配置管理工具来自动化部署过程,提升效率和可靠性。
353 13
|
4月前
|
安全 Java 数据库
Spring Boot 框架深入学习示例教程详解
本教程深入讲解Spring Boot框架,先介绍其基础概念与优势,如自动配置、独立运行等。通过搭建项目、配置数据库等步骤展示技术方案,并结合RESTful API开发实例帮助学习。内容涵盖环境搭建、核心组件应用(Spring MVC、Spring Data JPA、Spring Security)及示例项目——在线书店系统,助你掌握Spring Boot开发全流程。代码资源可从[链接](https://pan.quark.cn/s/14fcf913bae6)获取。
490 2
|
6月前
|
人工智能 缓存 自然语言处理
保姆级Spring AI 注解式开发教程,你肯定想不到还能这么玩!
这是一份详尽的 Spring AI 注解式开发教程,涵盖从环境配置到高级功能的全流程。Spring AI 是 Spring 框架中的一个模块,支持 NLP、CV 等 AI 任务。通过注解(如自定义 `@AiPrompt`)与 AOP 切面技术,简化了 AI 服务集成,实现业务逻辑与 AI 基础设施解耦。教程包含创建项目、配置文件、流式响应处理、缓存优化及多任务并行执行等内容,助你快速构建高效、可维护的 AI 应用。
|
8月前
|
Java 应用服务中间件 Scala
Spring Boot 实现通用 Auth 认证的 4 种方式
本文介绍了在Spring Boot中实现通用Auth的四种方式:传统AOP、拦截器(Interceptor)、参数解析器(ArgumentResolver)和过滤器(Filter)。每种方式都通过实例代码详细说明了实现步骤,并总结了它们的执行顺序。首先,Filter作为Servlet规范的一部分最先被调用;接着是Interceptor,它可以在Controller方法执行前后进行处理;然后是ArgumentResolver,在参数传递给Controller之前解析并验证参数
134 1