Spring Security 教程(27)、核心组件

Authentication:身份凭证

core-components 配图
core-components 配图
core-components 配图

Authentication 是 Spring Security 的核心接口,代表当前请求者的身份信息。

1
2
3
4
5
6
7
8
public interface Authentication extends Principal, Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
Object getCredentials();
Object getDetails();
Object getPrincipal();
boolean isAuthenticated();
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}

最常用的实现是 UsernamePasswordAuthenticationToken:

1
2
3
4
5
6
7
8
9
10
11
12
// 未认证状态
UsernamePasswordAuthenticationToken unauthenticated =
new UsernamePasswordAuthenticationToken("admin", null);

// 已认证状态
UsernamePasswordAuthenticationToken authenticated =
new UsernamePasswordAuthenticationToken(
"admin", // principal(用户主体)
"password", // credentials(凭据)
AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN")
);
authenticated.setAuthenticated(true);

GrantedAuthority:权限标识

GrantedAuthority 代表一个权限或角色。最常见的实现是 SimpleGrantedAuthority:

1
2
3
GrantedAuthority roleAdmin = new SimpleGrantedAuthority("ROLE_ADMIN");
GrantedAuthority roleUser = new SimpleGrantedAuthority("ROLE_USER");
GrantedAuthority permissionRead = new SimpleGrantedAuthority("USER_READ");

注意:ROLE_ 前缀是约定俗成的,不是强制的。但 hasRole() 方法会自动添加这个前缀,所以建议使用这个约定。

SecurityContext:安全上下文

SecurityContext 持有当前请求的 Authentication 对象:

1
2
3
4
public interface SecurityContext extends Serializable {
Authentication getAuthentication();
void setAuthentication(Authentication authentication);
}

SecurityContextHolder:上下文持有者

SecurityContextHolder 通过 ThreadLocal 存储 SecurityContext,确保每个线程有独立的安全上下文:

1
2
3
4
5
6
7
8
// 获取当前认证信息
Authentication auth = SecurityContextHolder.getContext().getAuthentication();

// 设置当前认证信息
SecurityContextHolder.getContext().setAuthentication(authenticated);

// 清除当前认证信息
SecurityContextHolder.clearContext();

注意:ThreadLocal 在异步场景下可能失效。Spring Security 5.4+ 提供了 SecurityContextRepository 支持异步场景。

四者的协作关系

1
2
3
4
5
6
SecurityContextHolder (ThreadLocal)
└── SecurityContext
└── Authentication
├── Principal (用户名等标识信息)
├── Credentials (密码等凭据)
└── Collection<GrantedAuthority> (权限列表)

这个设计的关键优势是:认证信息一旦设置,整个请求处理链中的任何组件都可以访问它,无需逐层传递。