Spring Security(五)

登录用户数据的获取

在 Spring Security 中,用户登录信息本质上还是保存在HttpSession中,但为了方便使用,Spring Security 对HttpSession中的用户信息进行了封装。我们可以通过以下两种思路获取用户登录信息:

  1. 从SecurityContextHolder 中获取。
  2. 从当前请求对象中获取。

无论是哪种获取方式,都离不开Authentication,在Spring Security 中,Authentication 对象主要有两方面功能;

  1. 作为AuthenticationManager 的输入参数,提供用户身份认证的凭证,当它当作一个输入参数时,它的isAuthenticated方法返回的时false,表示用户还未认证。
  2. 代表已经经过身份认证的用户,此时的 Authentication 可以从 SecurityContext 中获取。

Authentication 主要包含三个方面的信息:

  1. principal:定义认证的用户。如果用户使用用户名/密码的方式登录,principal 通常就是一个UserDetails对象。
  2. credentials:登录凭证,一般就是指密码。当用户登录成功之后,登录凭证会被自动移除,以防止泄露。
  3. authorities:用户被授予的权限信息。
SecurityContextHolder

SecurityContextHolder.getContext() 是一个静态方法,也就意味着我们随时随地都可以获取到登录用户信息。如下:

@RestController
@RequestMapping("/user")
public class UserController {

    @GetMapping("/info")
    public void userInfo(){
        Authentication authentication = SecurityContextHolder
                    .getContext().getAuthentication();
        String name = authentication.getName();
        Collection<? extends GrantedAuthority> authorities = authentication
                        .getAuthorities();
    }
}

SecurityContextHolder 中存储的是SecurityContext ,SecurityContext 中存储的是Authentication,三者关系如下:
在这里插入图片描述
SecurityContextHolder 中定义了三种不同的数据存储策略。(典型的策略模式)

  1. MODE_THREADLOCAL :这种存放策略是将SecurityContext 存放在ThreadLocal中,ThreadLocal 的特点是在哪个线程中存储就要在哪个线程中读取。这也是SecurityContextHolder 的默认存储策略,这种存储策略意味着如果在具体的业务处理代码中,开启了子线程,在子线程中去获取登录用户数据,就会获取不到。
  2. MODE_INHERITABLETHREADLOCAL :这种存储模式适合于多线程环境,如果希望在子线程中也能够获取到登录用户的数据,那么可以采用这种存储模式。
  3. MODE_GLOBAL :这种存储模式实际是将数据保存到一个静态变量中,在Web开发中,很少使用。

Spring Security 中定义了SecurityContextHolderStrategy 接口来规范存储策略中的方法,如下:

public interface SecurityContextHolderStrategy {
    //用来清除存储的SecurityContext 对象
	void clearContext();
	//用来获取存储的SecurityContext 对象
	SecurityContext getContext();
	//用来设置存储的SecurityContext 对象
	void setContext(SecurityContext context);
	//用来创建一个空的SecurityContext 对象
	SecurityContext createEmptyContext();
}

在SecurityContextHolderStrategy 接口一共有三个实现类,对应三种不同的策略模式,如图:
在这里插入图片描述
ThreadLocalSecurityContextHolderStrategy:用ThreadLocal 作为存储数据的载体,所以针对SecurityContext 的清空、获取以及存储,都是在ThreadLocal 中进行操作的。SecurityContext 是一个接口,它只实现了SecurityContextImpl,所以创建就直接新建了一个SecurityContextImpl对象即可。

InheritableThreadLocalSecurityContextHolderStrategy:它和ThreadLocalSecurityContextHolderStrategy 的实现此策略基本一致,不同的是存储数据的载体变了,InheritableThreadLocalSecurityContextHolderStrategy 中是用InheritableThreadLocal ,InheritableThreadLocal继承了ThreadLocal,但是多了一个特性,就是在子线程创建的一瞬间,会自动将父线程中的数据复制到子线程中。正是利用这一特性,实现了子线程中获取用户的登录信息。

GlobalSecurityContextHolderStrategy:它是用一个静态方法来保存SecurityContext,所以它也可以在多线程环境下使用。但是一般在web开发中,这种存储策略使用的较少。

如果我们需要修改存储策略,可以配置VM options参数,如下;

-Dspring.security.strategy=MODE_INHERITABLETHREADLOCAL

这样子线程中也能获取到用户的信息了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值