Spring Security
0|1Spring Security和Shiro
框架名称 | 特点 | 应用 | 常用组合 |
---|---|---|---|
Spring Security | 功能更丰富,社区资源丰富 | 中大型的项目 | Spring Boot/Spring Cloud + Spring Security |
Shiro | 上手更加的简单 | 小项目 | SSM + Shiro |
0|1认证和授权
在Spring Security中就具体化为用户认证(Authentication)和用户授权(Authorization)两个部分。
用户认证
用户授权
0|1SpringBoot整合SpringSecurity
启动项目,控制台中会打印出来密码:
我们在浏览器中输入http://localhost:8080/user/list
直接跳转到http://localhost:8080/login
输入完毕后点击Sign in 说明登录成功 跳转到http://localhost:8080/user/list
运行出结果
修改用户名和密码
当前用户登录后,有没有权限去访问相应的请求
授权
0|1springsecurity的认证授权流程
Spring Security最核心的东西是一个过滤器链,这些过滤器在Spring boot启动的时候会帮我们配置上。
执行流程
文字描述话术:
具体的执行流程其实是一个过滤链:
1、用户向应用程序发起请求,请求需要经过Spring Security的过滤器链。
2、过滤器链首先会经过UsernamePasswordAuthenticationFilter过滤器,该过滤器判断请求是否是一个认证请求(如何知道是一个认证请求 拦截 对/login 的 POST 请求做拦截,校验表单中用户名,密码)。如果是认证请求,过滤器将获取请求中的用户名和密码,然后使用AuthenticationManager进行身份认证。
3、AuthenticationManager会根据用户名和密码创建一个Authentication对象,并将该对象传递给AuthenticationProvider进行认证。
4、AuthenticationProvider会根据传递过来的Authentication对象进行身份认证,并返回一个认证成功或失败的结果。
5、如果认证成功,UsernamePasswordAuthenticationFilter会将认证信息封装成一个Authentication对象,并将其放入SecurityContextHolder上下文中。
SecurityContextHolder
SecurityContextHolder上下文
session 一个用户在服务器上有一片空间 我们可以向这个空间中存放数据 只要是这个用户发送的请求 都可以共享这个空间的数据
SecurityContextHolder 用来获取登录之后用户信息。Spring Security 会将登录用户数据保存在 Session 中。但是,为了使用方便,Spring Security在此基础上还做了一些改进,其中最主要的一个变化就是线程绑定。当用户登录成功后,Spring Security 会将登录成功的用户信息保存到 SecurityContextHolder 中。SecurityContextHolder 中的数据保存默认是通过ThreadLocal 来实现的,使用 ThreadLocal 创建的变量只能被当前线程访问,不能被其他线程访问和修改,也就是用户数据和请求线程绑定在一起。当登录请求处理完毕后,Spring Security 会将 SecurityContextHolder 中的数据拿出来保存到 Session 中,同时将 SecurityContexHolder 中的数据清空。以后每当有请求到来时,Spring Security 就会先从 Session 中取出用户登录数据,保存到 SecurityContextHolder 中,方便在该请求的后续处理过程中使用,同时在请求结束时将 SecurityContextHolder 中的数据拿出来保存到 Session 中,然后将 Security SecurityContextHolder 中的数据清空。这一策略非常方便用户在 Controller、Service 层以及任何代码中获取当前登录用户数据。
6、用户请求获取资源时,会经过FilterSecurityInterceptor过滤器,该过滤器会根据请求的URL和HTTP方法获取访问控制列表(Access Control List)。
7、Access Control List会包含访问资源所需要的权限信息,FilterSecurityInterceptor会将Authentication对象和Access Control List传递给AccessDecisionManager进行授权决策。
8、AccessDecisionManager会调用多个AccessDecisionVoter进行投票,并根据投票结果来决定当前用户是否有访问该资源的权限。如果用户被授权访问资源,应用程序将返回资源的响应结果。
总结就是首先经过认证过滤器实现认证,认证成功的话就会将用户信息存到authentication对象里面放到security上下文去(后续的权限校验需要获取到),这里面是包括权限的,之后再由AccessDecisionManager去根据相关策略进行权限鉴定
UsernamePasswordAuthenticationFilter 在org.springframework.security.web.authentication包下 可以查看源码
ProviderManager
ProviderManager 在 org.springframework.security.authentication包下 可以查看源码 他实现了AuthenticationManager这个接口
因为是表单提交 所以调用的是DaoAuthenticationProvider
核心组件介绍:
Authentication
Authentication是一个接口,用来表示用户认证信息。
该对象主要包含了用户的详细信息(UserDetails)和用户鉴权时所需要的信息,如用户提交的用户名密码、Remember-me Token,或者digest hash值等。按不同鉴权方式使用不同的Authentication实现。
在用户登录认证之前相关信息会封装为一个Authentication具体实现类的对象,在登录认证成功之后又会生成一个信息更全面,包含用户权限等信息的Authentication对象,然后把它保存在 SecurityContextHolder所持有的SecurityContext中,供后续的程序进行调用,如访问权限的鉴定等。
接口中的方法:
从这个接口中,我们可以得到用户身份信息,密码,细节信息,认证信息,以及权限列表,具体的详细解读如下:
getAuthorities(): 用户权限信息(权限列表),通常是代表权限的字符串列表;
getCredentials(): 用户认证信息(密码信息),由用户输入的密码凭证,认证之后会移出,来保证安全性;
getDetails(): 细节信息,Web应用中一般是访问者的ip地址和sessionId;
getPrincipal(): 用户身份信息,在未认证的情况下获取到的是用户名,在已认证的情况下获取到的是 UserDetails (UserDetails也是一个接口,里边的方法有getUsername,getPassword等);
isAuthenticated: 获取当前 Authentication 是否已认证;
setAuthenticated: 设置当前 Authentication 是否已认证(true or false)。
官方文档里说过,当用户提交登陆信息时,会将用户名和密码进行组合成一个实例UsernamePasswordAuthenticationToken,而这个类是Authentication的一个常用的实现类,用来进行用户名和密码的认证,类似的还有RememberMeAuthenticationToken,它用于记住我功能。
GrantedAuthority
Authentication的getAuthorities()方法返回一个 GrantedAuthority 对象数组。
GrantedAuthority该接口表示了当前用户所拥有的权限(或者角色)信息,用于配置 web授权、方法授权、域对象授权等。该属性通常由UserDetailsService 加载给 UserDetails。这些信息由授权负责对象AccessDecisionManager来使用,并决定最终用户是否可以访问某资源(URL或方法调用或域对象)。鉴权时并不会使用到该对象。
如果一个用户有几千个这种权限,内存的消耗将会是非常巨大的。
5.UserDetails
UserDetails存储的就是用户信息,它和Authentication接口类似,都包含了用户名,密码以及权限信息。
而区别就是Authentication中的getCredentials来源于用户提交的密码凭证,而UserDetails中的getPassword取到的则是用户正确的密码信息,认证的第一步就是比较两者是否相同,除此之外,Authentication#getAuthorities是认证用户名和密码成功之后,由UserDetails#getAuthorities传递而来。而Authentication中的getDetails信息是经过了AuthenticationProvider认证之后填充的。
其接口方法含义如下:
getAuthorites:获取用户权限,本质上是用户的角色信息。
getPassword: 获取密码。
getUserName: 获取用户名。
isAccountNonExpired: 账户是否过期。
isAccountNonLocked: 账户是否被锁定。
isCredentialsNonExpired: 密码是否过期。
isEnabled: 账户是否可用。
0|1完成自定义的认证授权流程
1.UsernamePasswordAuthenticationFilter这个过滤器如何知道我们提交的是登录操作,
2.去数据库验证用户名和密码的操作应该写在什么地方?
我们需要进行自定义配置
导入以下依赖:
五张表
登录验证的是t_user表
权限和角色分布在t_role和t_permission表中
实体类的创建(略 )自行完成
对应的mapper文件和映射文件的创建(略)
表数据请参考资料中的offcnpe.sql文件
业务逻辑层的编写如下
我们自定义一个业务逻辑层实现类
controller上编写
在浏览器中访问http://localhost:8080/user/list 因为未登录会直接被spring security打到登录页面,
在登录页面输入 admin 密码是123456 这个人的角色时ROLE_ADMIN可以直接在页面输出哈哈
如果在登录页面输入 xiaoming 密码是123456 这个人的角色不是ROLE_ADMIN 所以会跳转到403页面
自定义登录失败和权限认证失败的内容返回给客户端,不要直接打印出来403页面或者登录失败
AccessDeineHandler 用来解决认证过的用户访问无权限资源时的异常
AuthenticationFailureHandler 用来解决登录失败的异常
0|1总结
常见的过滤器
【1】WebAsyncManagerIntegrationFilter
将 Security 上下文与 Spring Web 中用于处理异步请求映射的 WebAsyncManager 进行集成。
【2】SecurityContextPersistenceFilter
在每次请求处理之前将该请求相关的安全上下文信息加载到 SecurityContextHolder 中,然后在该次请求处理完成之后,将 SecurityContextHolder 中关于这次请求的信息存储到一个“仓储”中,然后将 SecurityContextHolder 中的信息清除,例如在Session中维护一个用户的安全信息就是这个过滤器处理的。
【3】HeaderWriterFilter
用于将头信息加入响应中。
【4】CsrfFilter
用于处理跨站请求伪造。
【5】LogoutFilter
用于处理退出登录。
【6】UsernamePasswordAuthenticationFilter
用于处理基于表单的登录请求,从表单中获取用户名和密码。默认情况下处理来自 /login 的请求。从表单中获取用户名和密码时,默认使用的表单 name 值为 username 和 password,这两个值可以通过设置这个过滤器的usernameParameter 和 passwordParameter 两个参数的值进行修改
【7】DefaultLoginPageGeneratingFilter
如果没有配置登录页面,那系统初始化时就会配置这个过滤器,并且用于在需要进行登录时生成一个登录表单页面。
【8】BasicAuthenticationFilter
检测和处理 http basic 认证。
【9】RequestCacheAwareFilter
用来处理请求的缓存。
【10】SecurityContextHolderAwareRequestFilter
主要是包装请求对象request。
【11】AnonymousAuthenticationFilter
检测 SecurityContextHolder 中是否存在 Authentication 对象,如果不存在为其提供一个匿名 Authentication。
【12】SessionManagementFilter
管理 session 的过滤器。
【13】ExceptionTranslationFilter
处理 AccessDeniedException 和 AuthenticationException 异常。该过滤器不需要我们配置,对于前端提交的请求会直接放行,捕获后续抛出的异常并进行处理(例如:权限访问限制)。
【14】FilterSecurityInterceptor
可以看做过滤器链的出口。该过滤器是过滤器链的最后一个过滤器,根据资源权限配置来判断当前请求是否有权限访问对应的资源。如果访问受限会抛出相关异常,并由ExceptionTranslationFilter过滤器进行捕获和处理。
【15】RememberMeAuthenticationFilter
当用户没有登录而直接访问资源时, 从 cookie 里找出用户的信息, 如果 Spring Security 能够识别出用户提供的remember me cookie, 用户将不必填写用户名和密码, 而是直接登录进入系统,该过滤器默认不开启。
0|1常见的验证授权流程
一、Session-Cookie 机制 (web应用中最常见的)
当服务端需要对访问的客户端进行身份认证时,常用的做法是通过session-cookie 机制流程
Session-Cookie 认证存在的问题:
当客户访问量增加,服务端需要存储大量的session会话,对服务端有很大考验
当服务端为集群时,用户登录其中一台服务器,会将session保存在该服务器的内存中,
但是当用户访问其他服务器时。会无法访问。(已经有了成熟的解决方案)可以采用使用缓存服务器来保证共享 第三方缓存来保存session由于依赖cookie,所以存在CSRF安全问题
前后端分离项目不共享session 演示问题
二、Token 认证机制:
//http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
使用Jwt
0|1跨域概念
0|1跨域问题
spring security 框架CsrfFilter权限高于@CrossOrigin
需要在配置类中关闭spring security的跨域保护
关闭表单登录
配置放行界面
告诉spring security不需要再把认证过的数据往session存放
0|1自定义过滤器
表单登录失败
已登陆权限不足跳转
非表单登陆失败
表单登录成功处理器
token验证登录状态
加载过滤器
controller中登录判定
__EOF__
作 者:YXH
出 处:https://www.cnblogs.com/YxinHaaa/p/17583550.html
关于博主:编程路上的小学生,热爱技术,喜欢专研。评论和私信会在第一时间回复。或者直接私信我。
版权声明:署名 - 非商业性使用 - 禁止演绎,协议普通文本 | 协议法律文本。
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库