ethanzhl

V1

2023/01/08阅读:18主题:全栈蓝

Spring Security 基本概念

核心功能

对于一个安全框架而言,无论是Shiro还是Spring Security,最核心的功能,无非就是如下两个方面

  • 认证
  • 授权

通俗点讲,认证就是身份验证(你是谁?),授权就是访问控制(你可以做什么?)

认证

用户的认证信息主要是由 Authentication的实现类来保存

public interface Authentication extends PrincipalSerializable {

  Collection<? extends GrantedAuthority> getAuthorities();

  Object getCredentials();

  Object getDetails();

  Object getPrincipal();

  boolean isAuthenticated();

  void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}

这里接口中定义的方法如下:

  • getAuthorities用来获取用户的权限
  • getCredentials用来获取用户的凭证,一般来说就是密码
  • getDetails用来获取用户携带的详细信息,可能是当前请求之类等
  • getPrincipal用来获取当前用户,例如是一个用户名或者一个用户对象
  • isAuthenticated当前用户是否认证成功

AuthenticationManager

认证工作主要是由AuthenticationManager接口来负责

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

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

  • 返回Authentication,表示认证成功
  • 抛出AuthenticationException,表示拥护输入了无效的凭证
  • 返回Null,表示不能断定

ProviderManager

AuthenticationManager最主要的实现类就是ProviderManager

public class ProviderManager implements AuthenticationManagerMessageSourceAwareInitializingBean {
    ......
    
    private List<AuthenticationProvider> providers = Collections.emptyList();
    
    ......
}

ProviderManager管理了众多的AuthenticationProvider实例

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(例如,项目同时支持form表单登录和短信验证码登录),多个AuthenticationProvider统一由ProviderManager来管理。同时,ProviderManager具有一个可选的parent,如果所有的AuthenticationProvider都认证失败,那么就会调用parent进行认证。parent相当于一个备用认证方式,即各个AuthenticationProvider都无法处理认证问题的时候,就由parent出场收拾残局。

授权

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

  • AccessDecisionManager
  • AccessDecisionVoter

AccessDecisionManager

public interface AccessDecisionManager {
  
  void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException;

  boolean supports(ConfigAttribute attribute);

  boolean supports(Class<?> clazz);
}

AccessDecisionManager是一个决策器,来决定此次访问是否被允许。

AccessDecisionVoter

public interface AccessDecisionVoter<S{

  int ACCESS_GRANTED = 1;
  int ACCESS_ABSTAIN = 0;
  int ACCESS_DENIED = -1;

  boolean supports(ConfigAttribute attribute);

  boolean supports(Class<?> clazz);

  int vote(Authentication authentication, S object, Collection<ConfigAttribute> attributes);
}

AccessDecisionVoter是一个投票器,投票器会检查用户是否具备应有的角色,进而投出赞成、反对、弃权票。

AccessDecisionVoterAccessDecisionManager都有众多的实现类,在AccessDecisionManager中会挨个遍历AccessDecisionVoter,进而决定是否允许用户访问,因而AccessDecisionVoterAccessDecisionManager两者的关系类似于AuthenticationProviderProviderManager的关系。

ConfigAttribute

public interface ConfigAttribute extends Serializable {

  String getAttribute();
  
}

在Spring Security 中,用户请求一个资源(通常是一个网络接口或者一个java方法)所需要的角色会被封装成一个ConfigAttribute对象,ConfigAttribute中只有一个getAttribute方法,该方法返回一个String字符串,就是角色的名称。一般来说,角色名称都带有一个**ROLE_**前缀,投票器AccessDecisionVoter所做的事情,其实就是比较用户所具备的角色和请求某个资源所需要的ConfigAttribute之间的关系。

Web 安全

在Spring Security中,认证、授权等功能都是基于过滤器来完成的。

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

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

FilterChainProxy作为一个顶层管理者,将统一管理Security Filter。FilterChainProxy本身将通过Spring框架提供的DelegatingFilterProxy整合到原生过滤器链中,所以图1-2 还可以做进一步优化,如图1-3所示。

分类:

后端

标签:

Java

作者介绍

ethanzhl
V1