如何在spring security手动自定义用户认证SecurityContextHolder设置Authentication?

正常情况下,我们登录都是用账号密码登录,spring security的登录逻辑是在UsernamePasswordAuthenticationFilter里,这个类继承了AbstractAuthenticationProcessingFilter,我们如果想实现自己的登陆判断业务逻辑,可以继承AbstractAuthenticationProcessingFilter来实现,然后 http.addFilterAt(new MyUsernamePasswordFilter(), UsernamePasswordAuthenticationFilter.class) 这样就替换成自己的filter了。

UsernamePasswordAuthenticationFilter里的这段源码会把登录成功后的用户token信息放入上下文。

 1 public Authentication attemptAuthentication(HttpServletRequest request,
 2             HttpServletResponse response) throws AuthenticationException {
 3     if (postOnly && !request.getMethod().equals("POST")) {
 4         throw new AuthenticationServiceException(
 5             "Authentication method not supported: " + request.getMethod());
 6     }
 7 
 8     String username = obtainUsername(request);
 9     String password = obtainPassword(request);
10 
11     if (username == null) {
12         username = "";
13     }
14 
15     if (password == null) {
16         password = "";
17     }
18 
19     username = username.trim();
20 
21     UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
22         username, password);
23 
24     // Allow subclasses to set the "details" property
25     setDetails(request, authRequest);
26 
27     return this.getAuthenticationManager().authenticate(authRequest);
28 }

如果我不用上面的方法,自己在某个方法里需要实现登录并且session共享的功能,可以这样写。

 1 UserInfo userInfo = (UserInfo) userDetailsService.loadUserByUsername(username);
 2 UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userInfo, password, userInfo.getAuthorities());
 3 
 4 // 设置authentication中details
 5 authentication.setDetails(new WebAuthenticationDetails(request));
 6 
 7 SecurityContextHolder.getContext().setAuthentication(authentication);
 8 
 9 // 在session中存放security context,方便同一个session中控制用户的其他操作
10 HttpSession session = request.getSession(true);
11 // 这一步很关键,不能省略掉
12 session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());

SecurityContextHolder是SpringSecurity最基本的组件了,是用来存放SecurityContext的对象,默认是使用ThreadLocal实现的,这样就保证了本线程内所有的方法都可以获得SecurityContext对象。

SecurityContextHolder可以工作在以下三种模式之一:
1)MODE_THREADLOCAL (缺省工作模式)
2)MODE_GLOBAL
3) MODE_INHERITABLETHREADLOCAL
4) 修改SecurityContextHolder的工作模式有两种方法 :
a: 设置一个系统属性(system.properties) : spring.security.strategy;
SecurityContextHolder会自动从该系统属性中尝试获取被设定的工作模式
b: 调用SecurityContextHolder静态方法setStrategyName()

SecurityContextHolder存储SecurityContext的方式(默认就是mode_threadlocal)

使用SecurityContextHolder获取当前登录的用户信息
在SecurityContextHolder中保存的是当前访问者的信息。Spring Security使用一个Authentication对象来表示这个信息。一般情况下,我们都不需要创建这个对象,在登录过程中,Spring Security已经创建了该对象并帮我们放到了SecurityContextHolder中。从SecurityContextHolder中获取这个对象也是很简单的。

 1 SecurityContextHolder.getContext().getAuthentication(); 

这样在其它接口里就可以拿到上面设置的用户信息了。

posted @ 2022-10-18 17:17  夏威夷8080  阅读(1562)  评论(0)    收藏  举报