浅谈SpringSecurity基本原理

网友投稿 233 2023-01-12

浅谈SpringSecurity基本原理

一、SpringSecurity 本质

SpringSecurity 本质是一个过滤器链;

从启动是可以获取到(加载)过滤器链,当执行请求时就会执行相应的过滤器:

org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter

org.springframework.security.web.context.SecurityContextPersistenceFilter

org.springframework.security.web.header.HeaderWriterFilter

org.springframework.security.web.csrf.CsrfFilter

org.springframework.security.web.authentication.logout.LogoutFilter

org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter

org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter

org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter

org.springframework.security.web.savedrequest.RequestCacheAwareFilter

org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter

org.springframework.security.web.authentication.AnonymousAuthenticationFilter

org.springframework.security.web.session.SessionManagementFilter

org.springframework.security.web.access.ExceptionTranslationFilter

org.springframework.security.web.access.intercept.FilterSecurityInterceptor

二、典型过滤器

2.1 FilterSecurityInterceptor

FilterSecurityInterceptor:是一个方法级的权限过滤器, 基本位于过滤链的最底部。

1.打开FilterSecurityInterceptor类,发现该类是实现Filter接口,如图所示:

2.找到doFilter方法,发现最后调用的是invoke方法

3.找到invoke方法

super.beforeInvocation(filterInvocation) 表示查看之前的 filter 是否通过。

filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse());表示真正的调用后台的服务。

2.2 ExceptionTranslationFilter

ExceptionTranslationFilter:是个异常过滤器,用来处理在认证授权过程中抛出的异常

1.点击继承方法,发现该类是实现Filter接口,如图所示:

2.找到核心方法doFilter方法

2.3 UsernamePasswordAuthenticationFilter

UsernamePasswordAuthenticationFilter :对/login 的 POST 请求做拦截,校验表单中用户名,密码。

1.找到核心方法attemptAuthentication

三、过滤器加载过程

1.使用Spring Security首先是需要进行配置,而springboot帮我们做了这些事情,自动装配省了配置。

本质是有过滤器进行处理的DelegatingFilterProxy,找到doFilter方法,进入initDelegate方法

2.该方法主要是找到指定的过滤器名(FilterChainProxy)

wac:spring容器中上下文对象。

Filter delegate = wac.getBean(targetBeanName, Filter.class);//获取Spring容器中beanName=targetBeanName,类型为Filter的bean

3.我能从第二步知道获得的过滤器名FilterChainProxy,所以我们进入这个类看看

发现无论怎么处理都会调用doFilterInternal,很好奇

4.我们进入doFilterInternal看看,发现代码中有个list集合是来装每个过滤器的

5.getFilters方法把过滤器都加载到过滤链中

6.返回DelegatingFilterProxy类中的doFilter方法,调用invokeDelegate,调用代理对象方法,完成拦截

7.invokeDelegate方法中delegate调用代理对象的Filter完成拦截

四、两个重要接口

4.1 UserDetailsService接口

当什么也没有配置的时候,账号和密码是由 Spring Security 定义生成的。而在实际项目中账号和密码都是从数据库中查询出来的。 所以我们要通过自定义逻辑控制认证逻辑。

UserDetailsService接口:查询数据库中的用户名和密码

agfcdB UsernamePasswordAuthenticationFilter:获取前台表单传过来的用户名和密码

返回值 UserDetails,这个类是系统默认的用户“主体”

UserDetails.java

// 表示获取登录用户所有权限

Collection extends GranagfcdBtedAuthority> getAuthorities();

// 表示获取密码

String getPassword();

// 表示获取用户名

String getUsername();

// 表示判断账户是否过期

boolean isAccountNonExpired();

// 表示判断账户是否被锁定

boolean isAccountNonLocked();

// 表示凭证{密码}是否过期

boolean isCredentialsNonExpired();

// 表示当前用户是否可用

boolean isEnabled();

UserDetails的实现类,以后我们只需要使用 User 这个实体类即可!

方法参数 username:表示用户名。此值是客户端表单传递过来的数据。默认情况下必须叫 username,否则无法接收。

4.2 PasswordEncoder接口

PasswordEncoder接口:用来数据加密

PasswordEncoder.java

// 表示把参数按照特定的解析规则进行解析

String encode(CharSequence rawPassword);

// 表示验证从存储中获取的编码密码与编码后提交的原始密码是否匹配。如果密码匹

配,则返回 true;如果不匹配,则返回 false。第一个参数表示需要被解析的密码。第二个

参数表示存储的密码。

boolean matches(CharSequence rawPassword, String encodedPassword);

// 表示如果解析的密码能够再次进行解析且达到更安全的结果则返回 true,否则返回

false。默认返回 false。

default boolean upgradeEncoding(String encodedPassword) {

return false; }

PasswordEncoder的实现类:

BCryptPasswordEncoder 是 Spring Security 官方推荐的密码解析器,平时多使用这个解析器。

BCryptPasswordEncoder 是对 bcrypt 强散列方法的具体实现。是基于 Hash 算法实现的单向加密。可以通过 http://strength 控制加密强度,默认10.

查用方法演示:

@Test

public void test01(){

// 创建密码解析器

BCryptPasswordEncoder bCryptPasswordEncoder = new

BCryptPasswordEncoder();

// 对密码进行加密

String atguigu = bCryptPasswordEncoder.encode("atguigu");

// 打印加密之后的数据

System.out.println("加密之后数据:\t"+atguigu);

//判断原字符加密后和加密之前是否匹配

boolean result = bCryptPasswordEncoder.matches("atguigu", atguigu);

// 打印比较结果

System.out.println("比较结果:\t"+result);

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:详细总结Java创建文件夹的方法及优缺点
下一篇:springboot+vue实现登录功能
相关文章

 发表评论

暂时没有评论,来抢沙发吧~