6 Project Modules
6.1 Core
8
9 架构和实现
9.1 技术概览
9.1.1 运行环境
一句话没有特殊要求
9.1.2 核心组件
SecurityContextHolder,SecurityContext Authentication
SecurityContextHolder:有一个ThreadLocal 来存储 SecurityContext,因此每个线程有自己独立的SecurityContext,默认策略SecurityContextHolder.MODE_THREADLOCAL,你也可以自己配成SecurityContextHolder.MODE_GLOBAL或SecurityContextHolder.MODE_INHERITABLETHREADLOCAL
获得当前用户的信息
SecurityContextHolder 还存储当前用户的信息(Authentication)
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
String username = ((UserDetails)principal).getUsername();
} else {
String username = principal.toString();
}
UserDetails/UserDetailsService
UserDetails 用户信息接口
获得UserDeails的接口
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
UserDetailService实现有InMemoryDaoImpl和JdbcDaoImpl等
GrantedAuthority
Authentication提供的另外一个方法就是getAuthorities(),这个方法返回一个GrantedAuthority对象列表。GrantedAuthority即“角色”,如ROLE_ADMINISTRATOR或ROLE_HR_SUPERVISOR
9.1.3 Authentication
身份验证场景做的事情:
- 用户提交一个用户名和密码
- 系统验证密码的正确性
- 系统为用户获取上下文信息(用户角色等)
- 成功为用户创建安全上下文
- 用户访问权限控制
前4项的执行:
- UsernamePasswordAuthenticationToken(Authentication的一个实现)
- 验证通过将上面的token传给AuthenticationManager
- AuthenticationManager 返回一个填满数据的Authentication
- 安全上下文通过调用SecurityContextHolder.getContext().setAuthentication(..)来实现,传给它3中返回的Authentication
例子:
import org.springframework.security.authentication.*;
import org.springframework.security.core.*;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
public class AuthenticationExample {
private static AuthenticationManager am = new SampleAuthenticationManager();
public static void main(String[] args) throws Exception {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while(true) {
System.out.println("Please enter your username:");
String name = in.readLine();
System.out.println("Please enter your password:");
String password = in.readLine();
try {
Authentication request = new UsernamePasswordAuthenticationToken(name, password);
Authentication result = am.authenticate(request);
SecurityContextHolder.getContext().setAuthentication(result);
break;
} catch(AuthenticationException e) {
System.out.println("Authentication failed: " + e.getMessage());
}
}
System.out.println("Successfully authenticated. Security context contains: " +
SecurityContextHolder.getContext().getAuthentication());
}
}
class SampleAuthenticationManager implements AuthenticationManager {
static final List<GrantedAuthority> AUTHORITIES = new ArrayList<GrantedAuthority>();
static {
AUTHORITIES.add(new SimpleGrantedAuthority("ROLE_USER"));
}
public Authentication authenticate(Authentication auth) throws AuthenticationException {
if (auth.getName().equals(auth.getCredentials())) {
return new UsernamePasswordAuthenticationToken(auth.getName(),
auth.getCredentials(), AUTHORITIES);
}
throw new BadCredentialsException("Bad Credentials");
}
}
直接设置SecurityContextHolder内容
9.1.4 验证一个web应用
ExceptionTranslationFilter
负责处理AbstractSecurityInterceptor抛出的错误
AuthenticationEntryPoint
Authentication机制
请求之间存储SecurityContext
通过SecurityContextPersistenceFilter来将SecurityContext作为HttpSession属性的形式存储来实现
许多无状态RestFulweb应用不存储HTTPSession,也需要依赖SecurityContextPersistenceFileter来清理Session
9.1.5 访问控制Access-Control(Authorization)
访问控制决定对象AccessDecisionManager
AOP Advice
Secure与AbstractSecurityInterceptor
secure Object 指任何可以有security应用的对象,最常见的就是方法调用和web请求
每个受支持的secure Object 都有一个它自己的interceptor的类(作为AbstractInterceptor的子类)
AbstractSecurityInterceptor提供一下工作流来处理对象请求:
- 查找当前请求的configure Attributes
- 提交secure Object ,Authenciation 及 configure Attributes 给 AccessDecisionManager
- 调用发生时,可选的改变Authentication
- 如果访问被授权,允许调用继续进行
- 调用返回时,调用AfterInvocationManager
什么是Configuration Attributes
configuration Attributes 就是访问角色配置