Spring Security(二)

整体架构

认证

在Spring Security的架构设计中,认证(Authentication)和授权(Authorization)是分开的,无论使用什么样的认证都不影响授权,这是两个独立的存在,这种独立带来的好处之一,就是Spring Security可以非常方便的整合一些外部的认证方案。

在Spring Security中,用户的认证信息主要由Authentication的实现类来保存,Authentication接口定义如下:

public interface Authentication extends Principal, Serializable {
 	//用来获取用户的权限
	Collection<? extends GrantedAuthority> getAuthorities();
	//用来获取用户凭证,一般来说就是密码
	Object getCredentials();
	//用来获取用户携带的详细信息,可能是当前请求之类等
	Object getDetails();
	//用来获取当前用户,例如一个用户名或者一个用户对象
	Object getPrincipal();
	//当前用户是否认证成功
	boolean isAuthenticated();
	void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}

当用户使用用户名/密码登录或使用Remember-me登录时,都会对应一个不同的Authentication实例。
Spring Security 中的认证工作主要由AuthenticationManager接口来负责,接口定义如下:

public interface AuthenticationManager {
	Authentication authenticate(Authentication authentication)
			throws AuthenticationException;
}

AuthenticationManager中只有一个authenticate方法可以用来做认证,该方法有三个不同的返回值:

  • 返回Authentication,表示认证成功。
  • 抛出AuthenticationException异常,表示用户输入了无效的凭证。
  • 返回null,表示不能断定。

AuthenticationManager最主要的实现类是ProviderManager,ProviderManager管理了众多的AuthenticationProvider实例,AuthenticationProvider有点类似与AuthenticationManager,但是多了一个supports方法用来判断是否支持给定的Authentication类型。

public interface AuthenticationProvider {
	Authentication authenticate(Authentication authentication)
			throws AuthenticationException;
	boolean supports(Class<?> authentication);
}

由于Authentication拥有众多不同的实现类,这些不同的实现类又由不同的AuthenticationProvider来处理,所以AuthenticationProvider会有一个supports方法,用来判断当前的AuthenticationProvider是否支持对应的Authentication。

在一次完整的认证流程中,可能同时存在多个AuthenticationProvider,多个AuthenticationProvider统一由ProviderManager来管理。同时,ProviderManager具有一个可选的parent,如果所有的AuthenticationProvider都认证失败,那么就会调用parent进行认证。parent相当于一个具备认证方式,即各个AuthenticationProvider都无法处理认证问题的时候,就由parent出场了。

授权

完成认证后,接下来就是授权了,在Spring Security的授权体系中,有两个关键的接口:

  • AccessDecisionManager
  • AccessDecisionVoter

AccessDecisionVoter是一个投票器,它会检查用户是否具备对应的角色,进而投出赞成、反对或者弃票;AccessDecisionManager则是一个决策器,来决定此次访问是否被允许。AccessDecisionManager和AccessDecisionVoter都有众多的实现类,在AccessDecisionManager中挨个便 AccessDecisionVoter,进而决定是否允许用户访问,因而AccessDecisionVoter和AccessDecisionManager两者的关系类似于AuthenticationProvider和ProviderManager的关系。

在Spring Security中,用户请求一个资源(接口/方法)所需要的角色会封装成一个ConfigAttribute对象,在ConfigAttribute中只有一个getAttribute方法,该方法返回一个String字符串,就是角色名称。投票器AccessDecisionVoter所做的事情,其实就是比较用户所具备的角色和请求某个资源所需的ConfigAttribute之间的关系。

Web安全

在Spring Security中,认证、授权等功能都是基于过滤器来完成的。Spring Security常见的过滤器如下:
在这里插入图片描述
开发者所见到的Spring Security提供的功能,都是通过这些过滤器来实现的,这些过滤器按照既定的优先级排列,最终形成一个过滤器链。开发者也可以自定义过滤器,并通过@Order注解去调整自定义过滤器在过滤器链路中的位置。

默认过滤器并不是直接放在web项目的原生过滤器中,而是通过FilterChainProxy来统一管理。Spring Security中的过滤器链通过FilterChainProxy嵌入到Web项目的原生过滤器链中。

在Spring Security中,这样的过滤器不仅仅只有一个,可能会有多个。当存在多个过滤器链时,多个过滤器链之间要指定优先级,当请求到达之后,会从FilterChainProxy进行分发,先和哪个过滤器匹配上,就用哪个过滤器链进行处理。当系统存在多个不同的认证体系时,那么使用多个过滤器链就非常有效。

FilterChainProxy作为一个顶层管理者,将统一管理Security Filter。FilterChainProxy本身将通过Spring框架提供的DelegatingFilterProxy整合到原生过滤器链中。
在这里插入图片描述

登录数据保存

当用户登录成功后,Spring Security会将登录成功的用户信息保存到SecurityContentHolder中。SecurityContentHolder中的数据保存默认是通过ThreadLocal来实现的。使用ThreadLocal创建的变量只能被当前线程访问,不能被其他线程访问修改,也就是用户数据和请求线程绑定在一起。当登录请求处理完毕后,Spring Security会将SecurityContentHolder中的数据拿出来保存到Session中,同时将SecurityContentHolder中的数据清空,以后每当由请求到来时,Spring Security就会从Session中取出用户登录数据,保存到SecurityContentHolder中,方便在该请求的后续处理过程中使用,同时在请求结束时将SecurityContentHolder中的数据拿出来保存到Session中,然后清空SecurityContentHolder。

如果开发者使用@Async注解来开启异步任务的话,那么只需要添加如下配置,使用Spring Security提供的异步任务处理,就可以在异步任务中从SecurityContentHolder里边获取当前登录用户的信息。

@Configuration
public class ApplicationConfiguration extends AsyncConfigurerSupport{
	@Override
	public Executor getAsyncExecutor(){
		return new DelegatingSecurityContextExecutorService(
										Executors.newFixedThreadPool(5));
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Security提供了强大的身份认证和授权功能,但默认情况下只提供了一种单一的认证方式。如果你需要进行次认证,你可以按照以下步骤进行配置: 1. 创建一个自定义的AuthenticationProvider:你可以实现`AuthenticationProvider`接口创建一个自定义的认证提供者。在该实现中,你可以添加额外的认证逻辑,例如验证手机验证码、指纹等。 2. 配置Spring Security:在Spring Security的配置类中,注册你自定义的AuthenticationProvider。可以使用`AuthenticationManagerBuilder`的`authenticationProvider`方法来注册。例如: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomAuthenticationProvider customAuthenticationProvider; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(customAuthenticationProvider); } // 其他配置... } ``` 3. 实现次认证逻辑:在自定义的AuthenticationProvider中,实现`authenticate`方法来执行次认证逻辑。例如,你可以在该方法中调用其他认证接口或者验证用户输入的验证码等。如果认证成功,返回一个`Authentication`对象;如果认证失败,可以抛出`AuthenticationException`异常。 ```java @Component public class CustomAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { // 次认证逻辑,例如验证手机验证码 // 如果认证成功,返回一个Authentication对象 // 如果认证失败,可以抛出AuthenticationException异常 } @Override public boolean supports(Class<?> authentication) { return authentication.equals(UsernamePasswordAuthenticationToken.class); } } ``` 以上是一个基本的实现示例,你可以根据你的具体需求进行相应的调整和扩展。通过自定义AuthenticationProvider,你可以实现多种不同的认证方式,以满足不同场景下的次认证需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值