Spring Security自定义用户认证过程(1)

过前面对SpringSecurity安全过滤器工作原理的分析( [Spring Security安全过滤器工作原理](滑动验证页面)我们知道Spring Security的用户认证过程的工作原理大概为:

1. SecurityContextPersistenceFilter过滤器负责基于session的用户认证信息的管理。

2. UsernamePasswordAuthenticationFilter负责用户登录认证,认证成功后将认证信息写入SecurityContextHolder中。

3. FilterSecurityInterceptor负责验证当前用户是否符合当前请求的安全策略要求。

所以我们知道用户认证是在UsernamePasswordAuthenticationFilter过滤器完成的,如果我们要实现自定义的用户登录认证的话,只要想办法替换掉UsernamePasswordAuthenticationFilter过滤器中的原装缺省用户认证过程,应该就可以了。

接下来我们研究:

1. 什么是用户认证。

2. UsernamePasswordAuthenticationFilter过滤器的缺省认证过程。

3. 如何替换掉UsernamePasswordAuthenticationFilter的缺省用户认证过程。

#### 什么是用户认证

这个问题其实我们并不研究、只是声明,明确一下我们所要研究的问题的主题。

Spring Security官网overview部分开宗明义说明SpringSecurity是什么的时候就明确提过用户认证:

> Spring Security is a framework that provides authentication, authorization, and protection against common attacks.

说明用户认证是Spring Security的重要主题之一。

我们简化、明确一下今天要研究的用户认证这个主题实际就是:用户身份认证,让系统搞清楚你是否是合法用户的过程。

目前项目上或者我们见过的系统中用的最多的身份认证方式还是用户名、密码(或者短信验证码),用户身份认证其实包含两部分内容:

1. 身份确认:通过登录方式完成。

2. 身份保持及验证:就是登录验证完成之后,用户身份认证信息在保存以及后续的用户访问过程中的验证问题。

第一个问题比较简单明确,第二个问题就会引入两种不同的主流框架,主要区别是用户身份认证信息如何保存:

1. 服务器端保存:最常见的session方式。

2. 客户端持有:比如JWT的方式

我们今天要讨论的是***身份认证***的过程,忽略或简化身份信息的保存和持有过程,或者说我们就以传统的、Spring Security默认提供的通过session方式在服务器端持有用户身份认证信息的方式,来把今天研究的主题聚焦在***身份认证***这个问题上。

#### UsernamePasswordAuthenticationFilter过滤器的身份认证过程

先来认识几个概念:

1. Authentication:或者叫AuthenticationToken,默认实现是UsernamePasswordAuthenticationToken,用来持有请求上来的用户名、密码等信息,以及最终通过认证后的用户认证信息。

2. AuthenticationManager:认证管理器,由他来发起认证,但是他不完成认证,而是有他持有的AuthenticationProvider完成。

3. AuthenticationProvider:如上。

4. UserDetails:系统合法用户信息,比如你的系统的合法用户保存在数据库中,那么在发起认证的过程中就需要从数据库获取到后保存在UserDetails中,对应的有一个叫UserDetailsService的家伙,负责干这个事。

5. PasswordEncoder:顾名思义,密码编码器,系统用户的密码在系统中一定是以密文保存,前台提交上来的一般是明文,需要通过PasswordEncoder验密。说白了你的密码加密算法就是在PasswordEncoder中实现。

差不多够了,我们就用上面几个概念来说明一下UsernamePasswordAuthenticationFilter过滤器的用户登录认证过程。

第一步用request生成UsernamePasswordAuthenticationToken,此时生成的UsernamePasswordAuthenticationToken对象中只有前端登录页面传上来的用户名、密码,该token尚未完成认证。我们假设前台送上来的用户叫:user。前台录入的密码是:123456。

第二步,获取到AuthenticationManager进行认证,上面说过了,他是manager,他不干活,交给AuthenticationProvider去干。

第三步,AuthenticationProvider开始干活,他首先获取到UserDetailsService,让他获取到系统中叫user的用户信息,返回UserDetails对象(假设获取到了,对象名叫sysUser)。

第四步,依然是由AuthenticationProvider继续干,拿着前端送上来的用户名、密码(当前由UsernamePasswordAuthenticationToken对象持有)、以及后台获取到的用户对象(sysUser),交给PasswordEncoder去验密。

第五步,AuthenticationProvider继续拼命干活,如果认证通过的话(密码一样),重新生成一个UsernamePasswordAuthenticationToken,这是已经完成认证的token。

第六步,AuthenticationProvider干完活了交给经理AuthenticationManager,经理甩手把结果交给过滤器UsernamePasswordAuthenticationFilter。

第七步,过滤器把最终认证过的UsernamePasswordAuthenticationToken保存在SecurityContextHolder中,供后续过滤器、尤其是FilterSecurityInterceptor验证使用。

UsernamePasswordAuthenticationFilter完成使命!

#### 如何替换掉UsernamePasswordAuthenticationFilter的缺省用户认证过程

这个标题长的我有点不太适应,但是就这样吧。

这个问题你如果去百度或者google的话,会有很多不同的答案,我理解由于Spring Security本身是Spring家族的一员,与Spring或SpringBoot结合之后留给用户的客户化方式众多,所以我们可以任选其一进行客户化。

任何既能够实现你的目标、又没有给你的项目带来负面影响方案,都是可行的。

下面我们开始实现这一目标。

通过上面对UsernamePasswordAuthenticationFilter工作过程的分析,我们可以先设想一个思路:***替换掉上述第三步中的UserDetailsService,让我们自己的UserDetailsService干活,去获取我们自己的用户***。

我认为这是比较简单的方案,你当然可以替换掉整个UsernamePasswordAuthenticationFilter,但是这样的话你就相当于是替换掉了Spring Security的一个重要模块,你就可以怀疑他还是不是Spring Security了。

篇幅原因,本篇分析原理,下一篇文章具体操作。

上一篇 Spring Security的初始化过程(3)-CSDN博客

下一篇 Spring Security自定义用户认证过程(2)-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Security提供了很多默认的权限认证方式,但是我们也可以自定义权限认证方式。下面是一个简单的示例: 首先,我们需要实现一个自定义的UserDetailsService,该接口用于从数据库或其他数据源中获取用户信息。该接口中有一个方法loadUserByUsername,用于根据用户名获取用户信息。 ```java @Service public class CustomUserDetailsService implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username); if(user == null) { throw new UsernameNotFoundException("User not found with username: " + username); } return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), new ArrayList<>()); } } ``` 然后,我们需要创建一个自定义AuthenticationProvider,该类实现了Spring Security提供的AuthenticationProvider接口,用于自定义认证逻辑。在该类中,我们需要重写authenticate方法,该方法接收一个Authentication对象,该对象包含了用户输入的用户名和密码。我们可以通过该对象获取用户输入的用户名和密码,然后根据我们的认证逻辑进行认证,最后返回一个Authentication对象,该对象包含了认证后的用户信息。 ```java @Component public class CustomAuthenticationProvider implements AuthenticationProvider { @Autowired private CustomUserDetailsService userDetailsService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String username = authentication.getName(); String password = authentication.getCredentials().toString(); UserDetails userDetails = userDetailsService.loadUserByUsername(username); if(password.equals(userDetails.getPassword())) { return new UsernamePasswordAuthenticationToken(username, password, userDetails.getAuthorities()); } else { throw new BadCredentialsException("Invalid username/password"); } } @Override public boolean supports(Class<?> authentication) { return authentication.equals(UsernamePasswordAuthenticationToken.class); } } ``` 最后,我们需要在Security配置类中使用我们的自定义认证方式。我们可以通过重写configure(AuthenticationManagerBuilder auth)方法来配置我们的认证方式。 ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomAuthenticationProvider authProvider; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(authProvider); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic(); } } ``` 以上就是一个简单的Spring Security自定义权限认证的示例。通过自定义UserDetailsService和AuthenticationProvider,我们可以实现自己的认证逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值