
ethanzhl
2023/01/08阅读:18主题:全栈蓝
Spring Security 基本概念
核心功能
对于一个安全框架而言,无论是Shiro还是Spring Security,最核心的功能,无非就是如下两个方面
-
认证 -
授权
通俗点讲,认证就是「身份验证」(你是谁?),授权就是「访问控制」(你可以做什么?)
认证
用户的认证信息主要是由 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;
}
这里接口中定义的方法如下:
-
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 AuthenticationManager, MessageSourceAware, InitializingBean {
......
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
是一个投票器,投票器会检查用户是否具备应有的角色,进而投出赞成、反对、弃权票。
AccessDecisionVoter
和AccessDecisionManager
都有众多的实现类,在AccessDecisionManager
中会挨个遍历AccessDecisionVoter
,进而决定是否允许用户访问,因而AccessDecisionVoter
和AccessDecisionManager
两者的关系类似于AuthenticationProvider
和ProviderManager
的关系。
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所示。

作者介绍
