任何 Web 项目都离不开的 Spring Security【原理+实战(前后端分离+无状态)】

在这里插入图片描述

前言

大部分系统开发的第一个功能,基本上都是用户注册、登录,这两个看似简单的功能,实则是任何系统安全的基石。Spring Security 想必都很熟悉,作为一个安全管理框架,提供了丰富的认证机制、授权模型以及安全防护措施,极大简化了安全性的开发过程。本文就围绕 Spring Security 的架构原理、配置方法以及高级特性,高效的构建出一个安全的Web应用。

Spring Security 原理

本质

Spring Security 本质上就是一个过滤器链,所有的访问请求都会经过这些过滤器。如下图

Spring Security 过滤器链SecurityFilterChain

不了解过滤器的可以自行前往了解。

图中的 SecurityFilterChain 就是 Spring Security 的过滤器链,认证授权以及**安全防护(XSS、CSRF等)**都是在这些过滤器中完成的。

当项目中引入 Spring Security 启动后,一些默认的 SecurityFilterChain 过滤器会被装载,如下:

Spring Security 默认加载的过滤器

其中几个过滤器的命名直接体现了其功能,例如LogoutFilterUsernamePasswordAuthenticationFilterDefaultLoginPageGeneratingFilter等。

DefaultLoginPageGeneratingFilter生成页面就可以得知:Spring Security 默认是前后端不分离的。

所以,对于现在大多数前后端分离的项目,我们可以通过配置自定义需要哪些过滤器以及如何处理该功能,例如如何认证、认证失败、授权失败的响应等。

认证流程

开发者使用 Spring Security 最关心应该就是认证了,默认会提供表单认证,也就是生成一个表单页面,填写用户名和密码。如下图

这一功能就是DefaultLoginPageGeneratingFilter这个过滤器完成的。

用户名和密码默认由InMemoryUserDetailsManager提供,存储在内存中,这里自然需要我们后续去配置自定义实现

输入用户名密码后就可以去执行认证流程了,如下图

Spring Security认证流程

认证的流程中,我们还需要留意几个接口:

  1. SessionAuthenticationStrategy,认证成功后,会将用户会话存储在HttpSession中,在后续会基于HttpSession进行身份验证,但是对于无状态的应用,这种方式是不可取的。
  2. AuthenticationFailureHandlerAuthenticationSuccessHandler,默认的认证成功和失败后,会重定向跳转到某个页面,对于前后端分离的项目,这种方式时不可取的,依然需要我们后续去配置自定义实现

权限验证

通常,在认证时会将用户的权限信息(GrantedAuthority)加载给UserDetails,在后续的过滤器会对其进行验证,也就是ExceptionTranslationFilterAuthorizationFilter

这两个有什么区别?

Spring Security 支持请求URL和方法两种授权方式,即在配置中设置authorizeHttpRequests以及在方法上面的@PreAuthorize, @PostAuthorize注解。

以下是两者验证权限的流程

Authorize HttpServletRequests

Method Security

自定义配置

Spring Security 如何知道我们想要求所有用户都经过身份认证?如何知道我们想要支持基于表单的身份认证?实际上,全靠一个配置类去自定义设置,也就是上面所说的 SecurityFilterChain

接下来,就基于配置类构建一个前后端分离集成 Spring Security 的Web应用。

SpringBoot 集成 Spring Security

创建脚手架

SpringBoot 集成 Spring Security 很简单,去spring或者阿里脚手架下载一个demo,引入相关依赖就可以了,主要是这两个

项目启动后就会弹出【认证流程】中的登录界面。

如何配置就看自己的需求了,本文就以前后端分离、无状态为需求,结合JWT进行配置并实现。

Spring Security 如何配置

梳理下前后端分离、无状态以及结合JWT,应该如何配置Spring Security。

  1. 前后端分离需要配置以下几项:
    • 访问失败、认证失败、授权失败等响应改为json格式。
    • 由于是前后端分离,所以允许跨域请求。
  2. 无状态需要配置以下几项:
    • 对session的管理要设置为无状态。
    • 因为没有session,所以关闭csrf。
    • 在JWT中解析安全上下文(SecurityContext)验证,而不是在ThreadLocal中。

前后端分离&无状态配置

以上有几个事项直接配置即可,例如cors、csrf、session无状态、自定义登录等。

需要自定义实现的配置事项如下:

  1. 自定义登录配置后,需要自己写登录认证接口。
  2. 未认证时访问接口,默认会由 LoginUrlAuthenticationEntryPoint 处理,会重定向到某个URL,需要配置自定义为json响应。
  3. 认证失败后,默认会由SimpleUrlAuthenticationFailureHandler处理,会重定向到某个URL,需要配置自定义为json响应。
  4. 认证成功后,默认会由SavedRequestAwareAuthenticationSuccessHandler处理,会重定向到某个URL,需要配置自定义为json响应。
  5. 认证成功后,请求未授权的接口,默认会由AccessDeniedHandlerImpl处理,会重定向到某个URL,需要配置自定义为json响应。
  6. 注销成功后,默认会由SimpleUrlAuthenticationSuccessHandler,会重定向到某个URL,需要配置自定义为json响应。
  7. 整个流程中涉及到的安全上下文(SecurityContext),通过自定义过滤器,在token中解析并设置到当前请求的上下文。

整个配置大概是这样

自定义认证逻辑

通过以上简单的配置,就已经实现了前后端分离架构和无状态会话管理。除此之外,项目中还需要实现自定义认证逻辑。

以上的配置来看,当post请求/login,传入usernamepassword就会执行认证流程,不需要写/login接口。

那我们需要写哪些代码实现自定义认证逻辑?

认证流程(看图)中的AuthenticationManager,会调用 UserDetailsService 接口中的loadUserByUsername(),最终返回UserDetails对象交给Spring Security管理。

具体来说,我们需要创建两个类,一个实现UserDetailsService 接口,重写loadUserByUsername()加载用户信息,一个实现UserDetails,定义业务中的用户信息。

loadUserByUsername()中,我们只需要做几件事:

  1. 根据username获取用户信息,包括密码、角色和权限什么的,获取来源自定义,通常是关系型数据库,例如MySql。
  2. 如果该用户不存在,抛出异常即可。
  3. 将用户信息封装到UserDetails中,返回。

注意,这里不需要多此一举校验密码,认证流程中会有这一步骤。你只需将数据库中加密的密码交个UserDetails即可。

不需要写/login接口,认证成功后我想返回token怎么办?

如果有这样的疑问,那你一定是没好好看上面认证流程以及配置:代码中的formConfig.successHandler配置就是用来响应数据的。

完整的代码

为了方便大家观看,我将所有的代码放在一个文件中,如下图

注意:这只是一个示例代码,供大家学习了解Spring Security,可以参考,不建议直接在项目中使用。有任何问题可以随时交流。

总结

Spring Security 本质上就是一连串的过滤器,当一个请求来临时,这些过滤器会对该请求一一处理,包括登录认证、权限验证以及其他安全防护。也因其灵活性,我们只需有简单的配置加上一些代码就可以快速构建出一个安全性极高的Web应用。对于每次集成Spring Security都需要百度的开发者,希望在看完这篇文章的原理+实战后,可以让你摆脱此烦恼。

  • 19
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
本文介绍了一个基于Spring Boot、Spring Cloud和Vue前后分离项目实战。这个项目是一个简单的在线商城,包含了用户注册、登录、商品展示、购物车、订单管理等功能。通过这个项目,读者可以深入理解前后分离的架构模式和互联网应用的发方式。 首先,文章介绍了前后分离的基本概念和优势。前后分离是将应用的前和后代码分发,使得前和后具有独立的发周期和技术栈,进而提高了发效率和代码质量。同时,前后分离还可以提供更好的用户体验和灵活性,对于互联网应用来说尤为重要。 接下来,文章介绍了项目的架构和技术栈。项目采用了Spring Boot和Spring Cloud框架来实现后代码,采用MyBatis作为ORM框架和Redis作为缓存中间件。同时,项目还采用了Vue.js作为前框架和Element UI组件库来实现前页面。通过这些源框架和组件,可以快速搭建一个前后分离的互联网应用。 然后,文章介绍了项目的核心功能和代码实现。在用户注册和登录方面,项目采用了Spring Security框架和JWT令牌来实现用户认证和授权,保证了用户信息的安全性。在商品展示和购物车方面,项目采用了Vue.js来实现前页面和事件处理。在订单管理方面,项目采用了MyBatis Plus来实现订单数据的持久化和分页查询。 最后,文章介绍了项目的测试和优化。通过对项目的压力测试和性能测试,文章发现项目还存在一些性能瓶颈和安全隐患,可以通过优化数据库查询、缓存配置和代码实现来提高应用的性能和安全性。 总之,这篇文章介绍了一个基于Spring Boot、Spring Cloud和Vue前后分离项目实战,通过实现一个在线商城的功能,展示了前后分离发模式和互联网应用的发技术栈。本文可以作为前后分离发的入门教程,也可以作为互联网应用发的参考文档。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王二蛋!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值