SpringSecurity之SecurityContext和Authentication对象

下面开始讨论几个 Spring Security 里面的核心对象。

  • org.springframework.security.core.context.SecurityContext接口表示的是当前应用的安全上下文。通过此接口可以获取和设置当前的认证对象。
  • org.springframework.security.core.Authentication接口用来表示此认证对象。通过认证对象的方法可以判断当前用户是否已经通过认证,以及获取当前认证用户的相关信息,包括用户名、密码和权限等。

要使用Authentication认证对象,首先需要获取到 SecurityContext 对象。通过 org.springframework.security.core.context.SecurityContextHoldergetContext() 的静态方法 就可以获取。再通过 SecurityContext.getAuthentication()就可以得到Authentication。通过认证对象的 Authentication.getPrincipal() 方法就可以获得当前的认证主体

认证主体通常是 UserDetails 接口的实现,典型的认证过程就是当用户输入了用户名和密码之后,UserDetailsService通过用户名找到对应的 UserDetails 对象,接着比较密码是否匹配。如果不匹配,则返回出错信息;如果匹配的话,说明用户认证成功,就创建一个实现了 Authentication接口的对象,如 org.springframework.security. authentication.UsernamePasswordAuthenticationToken 类的对象。再通过 SecurityContext.setAuthentication() 方法来设置此认证对象。

//获取当前认证用户的用户名
public static String getAuthenticatedUsername() { 
   String username = null; 
   Object principal = SecurityContextHolder.getContext() 
       .getAuthentication().getPrincipal(); 
   if (principal instanceof UserDetails) { 
       username = ((UserDetails) principal).getUsername(); 
   } else { 
       username = principal.toString(); 
   } 
   return username; 
}

默认情况下(Web应用来说),SecurityContextHolder使用 ThreadLocal来保存 SecurityContext对象。因此,SecurityContext对象对于当前线程上所有方法都是可见的。这种实现对于 Web 应用来说是合适的。

不过在有些情况下,如桌面应用,这种实现方式就不适用了。Spring Security 允许开发人员对此进行定制。开发人员只需要实现接口 org.springframework.security.core.context.SecurityContextHolderStrategy并通过 SecurityContextHolder.setStrategyName(String)方法让 Spring Security 使用此实现即可。

另外一种设置方式是使用系统属性。Spring Security 默认提供了另外两种实现方式:

  • SecurityContextHolder.MODE_GLOBAL表示当前应用共享唯一的 SecurityContextHolder;
  • SecurityContextHolder.MODE_INHERITABLETHREADLOCAL表示子线程继承父线程的 SecurityContextHolder。
//使用全局唯一的 SecurityContextHolder的示例。
public void useGlobalSecurityContextHolder() { 
   SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_GLOBAL); 
}

你可能感兴趣的:(Spring,SpringBoot2启示录)