文章目录
- SpringSecurity 结构
- 组件:SecurityContextHolder
- 组件:Authentication
- 组件:UserDetailsService
- 组件:GrantedAuthority
- 组件总结
SpringSecurity 结构
在SpringSecurity中的jar分为4个,作用分别为
jar | 作用 |
---|---|
spring-security-core | SpringSecurity的核心jar包,认证和授权的核心代码都在这里面 |
spring-security-config | 如果使用Spring Security XML名称空间进行配置或Spring Security的 Java configuration支持,则需要它 |
spring-security-web | 用于Spring Security web身份验证服务和基于url的访问控制 |
spring-security-test | 测试单元 |
组件:SecurityContextHolder
在spring-security-core中的SecurityContextHolder,是一个非常基础的对象,存储了当前应用的上下文SecurityContext,而在SecurityContext可以获取Authentication对象。也就是当前认证的相关信息会存储在Authentication对象中。
默认情况下,SecurityContextHolder是通过 ThreadLocal
来存储对应的信息的。也就是在一个线程中我们可以通过这种方式来获取当前登录的用户的相关信息。而在SecurityContext中就只提供了对Authentication对象操作的方法
public interface SecurityContext extends Serializable {
Authentication getAuthentication();
void setAuthentication(Authentication authentication);
}
xxxStrategy的各种实现
策略实现 | 说明 |
---|---|
GlobalSecurityContextHolderStrategy | 把SecurityContext存储为static变量 |
InheritableThreadLocalSecurityContextStrategy | 把SecurityContext存储在InheritableThreadLocal中 InheritableThreadLocal解决父线程生成的变量传递到子线程中进行使用 |
ThreadLocalSecurityContextStrategy | 把SecurityContext存储在ThreadLocal中 |
组件:Authentication
Authentication是一个认证对象。在Authentication接口中声明了如下的相关方法。
public interface Authentication extends Principal, Serializable {
// 获取认证用户拥有的对应的权限
Collection<? extends GrantedAuthority> getAuthorities();
// 获取哦凭证
Object getCredentials();
// 存储有关身份验证请求的其他详细信息。这些可能是 IP地址、证书编号等
Object getDetails();
// 获取用户信息 通常是 UserDetails 对象
Object getPrincipal();
// 是否认证
boolean isAuthenticated();
// 设置认证状态
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}
基于上面讲解的三者的关系,在项目中如下来获取当前登录的用户信息了。
public String hello(){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Object principal = authentication.getPrincipal();
if(principal instanceof UserDetails){
UserDetails userDetails = (UserDetails) principal;
System.out.println(userDetails.getUsername());
return "当前登录的账号是:" + userDetails.getUsername();
}
return "当前登录的账号-->" + principal.toString();
}
调用 getContext()
返回的对象是 SecurityContext
接口的一个实例,这个对象就是保存在线程中的。接下来将看到,Spring Security中的认证大都返回一个 UserDetails
的实例作为principa。
组件:UserDetailsService
在上面的关系中可以看到在Authentication中存储当前登录用户的是Principal对象,而通常情况下Principal对象可以转换为UserDetails对象。UserDetails
是Spring Security中的一个核心接口。它表示一个principal,但是是可扩展的、特定于应用的。可以认为 UserDetails
是数据库中用户表记录和Spring Security在 SecurityContextHolder
中所必须信息的适配器。
public interface UserDetails extends Serializable {
// 对应的权限
Collection<? extends GrantedAuthority> getAuthorities();
// 密码
String getPassword();
// 账号
String getUsername();
// 账号是否过期
boolean isAccountNonExpired();
// 是否锁定
boolean isAccountNonLocked();
// 凭证是否过期
boolean isCredentialsNonExpired();
// 账号是否可用
boolean isEnabled();
}
而这个接口的默认实现就是 User
那么这个UserDetails对象什么时候提供呢?在上文介绍的数据库认证的Service中我们就用到了,有一个特殊接口 UserDetailsService
,在这个接口中定义了一个loadUserByUsername的方法,接收一个用户名,来实现根据账号的查询操作,返回的是一个 UserDetails
对象。
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
UserDetailsService接口的实现有如下:
Spring Security提供了许多 UserDetailsSerivice
接口的实现,包括使用内存中map的实现(InMemoryDaoImpl
低版本 InMemoryUserDetailsManager)和使用JDBC的实现(JdbcDaoImpl
)。但在实际开发中我们更喜欢自己来编写,比如UserServiceImpl我们的案例
/**
* UserService接口的实现类
*/
@Service
public class UserServiceImpl extends UserDetailsService {
@Autowired
UserMapper userMapper;
/**
* 根据账号密码验证的方法
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUser user = userMapper.queryByUserName(username);
System.out.println("---------->"+user);
if(user != null){
// 账号对应的权限
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
// 说明账号存在 {noop} 非加密的使用
UserDetails details = new User(user.getUserName()
,user.getPassword()
,true
,true
,true
,true
,authorities);
return details;
}
throw new UsernameNotFoundException("账号不存在...");
}
}
组件:GrantedAuthority
在Authentication中看到不光关联了Principal还提供了一个getAuthorities()方法来获取对应的GrantedAuthority对象数组。
public interface GrantedAuthority extends Serializable {
String getAuthority();
}
组件总结
核心对象 | 作用 |
---|---|
SecurityContextHolder | 用于获取SecurityContext |
SecurityContext | 存放了Authentication和特定于请求的安全信息 |
Authentication | 特定于Spring Security的principal |
GrantedAuthority | 对某个principal的应用范围内的授权许可 |
UserDetail | 提供从应用程序的DAO或其他安全数据源构建Authentication对象所需的信息 |
UserDetailsService | 接受String类型的用户名,创建并返回UserDetail |