写在前面
第一节中,我们基本上就引入SpringSecurity依赖,其他什么都没做就完成了认证功能。
之所以我们不用做什么,是因为SpringSecurity默认实现了很多功能。
当然了,这里默认实现都是基于内存的用户认证,即用户都是创建在内存当中的,现实应用都是基于数据库的。
小伙伴们不用着急,只要我们理解了基于内存的用户认证,那基于数据库也是一样的原理,不同的只是一个从内存中获取用户信息,一个从数据库中获取用户信息而已。
接下来,我们来简单看看其基本原理。
一、官方文档
官方文档对SpringSecurity 实现原理其实写的挺具体了。感兴趣的小伙伴可以点下面链接查看
https://docs.spring.io/spring-security/reference/servlet/architecture.html
但对于不少初学者,看官方文档可能会比较吃力。
所以晓凡将其简化,请接着往下看.
二、原理初探
我们以上一篇文章中案例,来看一下SpringSecurity流程。
SpringSecurity的原理其实就是一个过滤器链,如下图所示,每个过滤器各司其职。
上图中,并没有将全部过滤器都例举出来,刚开始,也没须要了解全部过滤器。
下面,我们来看看这几个主要过滤器
① UsernamePasswordAuthenticationFilter
这个过滤器处置惩罚用户登录的请求。
就像是保安查抄你的门禁卡和密码,确认你是不是小区的正当住民。
② ExceptionTranslationFilter
这个过滤器捕捉安全相干的异常,并将其转换为HTTP响应。
就像是保安发现了问题,他会采取相应的措施,好比不让你进入或者给你一个警告信息。
③ FilterSecurityInterceptor
这个过滤器是授权的核心,它决定用户是否有权限实行特定的请求。
就像是保安查抄你有没有权限去某个特定的地区。
三、 DefaultSecurityFilterChain类
为啥SpringSecurity默认帮我们实现那么多,其实主要是DefaultSecurityFilterChain的功劳,它加载了默认的15个Filter。
① 我们在源码中找到DefaultSecurityFilterChain 类,并如下图所示加上断点看一下
② 程序启动后,默认加载15个过滤器
四、各个过滤器作用
这里将例举出15个过滤器的作用,小伙伴们简单了解即可,切忌死记硬背,用得多了自然就记住了。
过滤器作用DisableEncodeUrlFilter用来禁用URL编码。有时候,为了防止CSRF攻击,Spring Security会对重定向的URL进行编码。但如果你确定你的应用环境是安全的,可以用这个过滤器来禁用这个功能。WebAsyncManagerIntegrationFilter确保异步请求也能正确处置惩罚安全上下文。就像是小区保安必要确保即使是快递或者外卖这样的非正常访问,也能被正确地记录和管理。SecurityContextHolderFilter确保每个请求都能正确地获取到安全上下文,也就是知道当前是谁在访问。就像是小区保安必要知道是谁在小区里。HeaderWriterFilter会在HTTP响应中添加一些安全相干的头部,好比防止XSS攻击的头部。就像是小区保安会在小区的围墙上安装一些安全设备。CsrfFilter防止跨站请求伪造攻击,确保用户的操作是他们自己发起的。就像是小区保安会查抄每个人的出入证,确保他们不是被坏人操控。LogoutFilter处置惩罚用户注销的请求,清除用户的身份信息。就像是小区保安在住民离开时,会注销他们的临时通行证。UsernamePasswordAuthenticationFilter处置惩罚基于用户名和密码的登录请求。就像是小区保安查抄住民的门禁卡和密码。DefaultLoginPageGeneratingFilter在必要时生成默认的登录页面。就像是小区保安会给没有门禁卡的访客一个标准的表格来填写信息。DefaultLogoutPageGeneratingFilter在必要时生成默认的注销页面。就像是小区保安会给必要离开的住民一个标准的流程来完成注销。BasicAuthenticationFilter处置惩罚基本的身份验证,也就是基于用户名和密码的认证,但不加密。就像是小区保安查抄住民的未加密的门禁卡和密码。RequestCacheAwareFilter记住用户最初的请求,如果因为认证被重定向,认证乐成后可以回到最初的页面。就像是小区保安记得你最初想去的地方,即使你必要去验证身份,回来后他还能指引你去那边。SecurityContextHolderAwareRequestFilter确保每个请求都能正确地访问到安全上下文。就像是小区保安确保每个访客都能被正确地记录和管理。AnonymousAuthenticationFilter为匿名用户创建一个认证 token。就像是小区保安会给没有门禁卡的访客一个临时的通行证。ExceptionTranslationFilter捕捉安全相干的异常,并将其转换为HTTP响应,好比401未授权或403克制访问。就像是小区保安在发现问题时,会采取相应的措施,好比不让进入或者给出一个错误信息。AuthorizationFilter负责查抄用户是否有权限实行特定的请求。就像是小区保安会查抄你有没有权限去某个特定的地区。五、基于内存的用户认证
在上面流程图中,我们提到了UsernamePasswordAuthenticationFilter 这个过滤器。用户认证就是在这个过滤器中完成的。
这个过滤器的职责就是:将内存中的用户信息获取出来,再和我们界面上输入的用户名和密码进行比较。
如果比较乐成,认证乐成,答应用户访问资源;如果比较失败,用户认证失败,拒绝访问。
5.1 认证流程
- 用户提交登录请求:用户在登录页面输入用户名和密码,然后提交给服务器。
- UsernamePasswordAuthenticationFilter拦截用户请求:这个过滤器会拦截登录请求,从请求中提取用户名和密码,创建一个UsernamePasswordAuthenticationToken对象。
- AuthenticationManager处置惩罚认证:UsernamePasswordAuthenticationFilter将UsernamePasswordAuthenticationToken通报给AuthenticationManager进行认证。
- ProviderManager遍历AuthenticationProvider:AuthenticationManager的默认实现ProviderManager会遍历全部的AuthenticationProvider,找到可以或许处置惩罚UsernamePasswordAuthenticationToken的DaoAuthenticationProvider。
- DaoAuthenticationProvider认证:DaoAuthenticationProvider会调用UserDetailsService的loadUserByUsername方法获取用户信息,然后使用PasswordEncoder对比密码。
- 认证乐成或失败:
- 如果密码正确,DaoAuthenticationProvider会创建一个新的Authentication对象,包罗用户的权限信息,返回给AuthenticationManager。
- 如果密码不正确,会抛出BadCredentialsException异常。
- SecurityContextHolder设置认证信息:认证乐成后,AuthenticationManager会将认证信息设置到SecurityContextHolder中。
- 用户登录乐成:用户登录乐成后,就可以访问系统资源了。
5.2 代码实现
信赖通过上面流程图,大家对认证流程已经很清晰了。
下面我们看看怎么把用户存入内存中,我们参照官方给出的实例即可
https://docs.spring.io/spring-security/reference/servlet/configuration/java.html
①创建一个WebSecurityConfig设置类:
②然后定义一个@Bean,范例是UserDetailsService,实现是InMemoryUserDetailsManager
具体代码如下- @Configuration //标明这个类为配置类,spring应用程序一启动,类中的been 就会被初始化在spring容器中
- @EnableWebSecurity //开启spring security 自定义配置
- public class WebSecurityConfig {
- @Bean
- public UserDetailsService userDetailsService(){
- //1、创建基于内存的用户管理器
- InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
- // 3、将第二步创建的UserDetail对象交给UserDetailsManager 管理
- inMemoryUserDetailsManager.createUser(
- //2、创建UserDetail 对象,用于管理用户名、用户密码、用户角色、用户权限
- //下面代码创建了一个用户名为user,密码为123456,角色为user的用户对象
- User.withDefaultPasswordEncoder()
- .username("user")
- .password("123456")
- .roles("user")
- .build());
- return inMemoryUserDetailsManager;
- }
- }
复制代码 通过上面设置类,在程序启动的时候。就会将用户名:user 密码:123456 角色:user这样一个用户存入内存中。
当用户想要获取资源时,就会走5.1末节认证流程。
六、小结
通过这篇的学习,我们知道了SpringSecurity 默以为我们干了些啥?基于内存的认证是怎么实现的?
当然了,现实开辟中,我们不可能把用户存于内存中,而是必要将用户存于数据库中。通过数据库获取用户和权限信息。
由于文章篇幅原因,这篇就到这儿了。下一篇我们来看看现实开辟中,怎么基于数据库进行认证。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |