Spring Security获取用户认证信息的实现流程

目录
  • 登录用户数据获取
    • SecurityContextHolder
    • SecurityContextHolderStrategy
  • 多线程情况下获取用户数据
  • 页面上获取用户信息

登录用户数据获取

SecurityContextHolder

​ Spring Security 会将登录用户数据保存在 Session 中。但是,为了使用方便,Spring Security在此基础上还做了一些改进,其中最主要的一个变化就是线程绑定。当用户登录成功后,Spring Security 会将登录成功的用户信息保存到 SecurityContextHolder 中。

​ SecurityContextHolder 中的数据保存默认是通过ThreadLocal 来实现的,使用 ThreadLocal 创建的变量只能被当前线程访问,不能被其他线程访问和修改,也就是用户数据和请求线程绑定在一起。当登录请求处理完毕后,Spring Security 会将 SecurityContextHolder 中的数据拿出来保存到 Session 中,同时将 SecurityContexHolder 中的数据清空。以后每当有请求到来时,Spring Security 就会先从 Session 中取出用户登录数据,保存到SecurityContextHolder 中,方便在该请求的后续处理过程中使用,同时在请求结束时将 SecurityContextHolder 中的数据拿出来保存到 Session 中,然后将SecurityContextHolder 中的数据清空。

​ 实际上 SecurityContextHolder 中存储是 SecurityContext,在 SecurityContext 中存储是 Authentication。

这种设计是典型的策略设计模式:

public class SecurityContextHolder {
	public static final String MODE_THREADLOCAL = "MODE_THREADLOCAL";
	public static final String MODE_INHERITABLETHREADLOCAL = "MODE_INHERITABLETHREADLOCAL";
	public static final String MODE_GLOBAL = "MODE_GLOBAL";
	private static final String MODE_PRE_INITIALIZED = "MODE_PRE_INITIALIZED";
	private static SecurityContextHolderStrategy strategy;
  //....
	private static void initializeStrategy() {
		if (MODE_PRE_INITIALIZED.equals(strategyName)) {
			Assert.state(strategy != null, "When using " + MODE_PRE_INITIALIZED
					+ ", setContextHolderStrategy must be called with the fully constructed strategy");
			return;
		}
		if (!StringUtils.hasText(strategyName)) {
			// Set default
			strategyName = MODE_THREADLOCAL;
		}
		if (strategyName.equals(MODE_THREADLOCAL)) {
			strategy = new ThreadLocalSecurityContextHolderStrategy();
			return;
		}
		if (strategyName.equals(MODE_INHERITABLETHREADLOCAL)) {
			strategy = new InheritableThreadLocalSecurityContextHolderStrategy();
			return;
		}
		if (strategyName.equals(MODE_GLOBAL)) {
			strategy = new GlobalSecurityContextHolderStrategy();
			return;
		}
    //.....
  }
}
  • MODE THREADLOCAL:这种存放策略是将 SecurityContext 存放在 ThreadLocal中,大家知道 Threadlocal 的特点是在哪个线程中存储就要在哪个线程中读取,这其实非常适合 web 应用,因为在默认情况下,一个请求无论经过多少 Filter 到达 Servlet,都是由一个线程来处理的。这也是 SecurityContextHolder 的默认存储策略,这种存储策略意味着如果在具体的业务处理代码中,开启了子线程,在子线程中去获取登录用户数据,就会获取不到。
  • MODE INHERITABLETHREADLOCAL:这种存储模式适用于多线程环境,如果希望在子线程中也能够获取到登录用户数据,那么可以使用这种存储模式。
  • MODE GLOBAL:这种存储模式实际上是将数据保存在一个静态变量中,在 JavaWeb开发中,这种模式很少使用到。

SecurityContextHolderStrategy

通过 SecurityContextHolder 可以得知,SecurityContextHolderStrategy 接口用来定义存储策略方法

public interface SecurityContextHolderStrategy {
	void clearContext();
	SecurityContext getContext();
	void setContext(SecurityContext context);
	SecurityContext createEmptyContext();
}

接口中一共定义了四个方法:

  • clearContext:该方法用来清除存储的 SecurityContext对象。
  • getContext:该方法用来获取存储的 SecurityContext 对象。
  • setContext:该方法用来设置存储的 SecurityContext 对象。
  • create Empty Context:该方法则用来创建一个空的 SecurityContext 对象。

代码中获取认证之后用户数据

@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String hello() {
      Authentication authentication = SecurityContextHolder
        .getContext().getAuthentication();
      User principal = (User) authentication.getPrincipal();
      System.out.println("身份 :"+principal.getUsername());
      System.out.println("凭证 :"+authentication.getCredentials());
      System.out.println("权限 :"+authentication.getAuthorities());
      return "hello security";
    }
}

多线程情况下获取用户数据

@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String hello() {
      new Thread(()->{
        Authentication authentication = SecurityContextHolder
          .getContext().getAuthentication();
        User principal = (User) authentication.getPrincipal();
        System.out.println("身份 :"+principal.getUsername());
        System.out.println("凭证 :"+authentication.getCredentials());
        System.out.println("权限 :"+authentication.getAuthorities());
      }).start();
      return "hello security";
    }
}

可以看到默认策略,是无法在子线程中获取用户信息,如果需要在子线程中获取必须使用第二种策略,默认策略是通过 System.getProperty 加载的,因此我们可以通过增加 VM Options 参数进行修改。

-Dspring.security.strategy=MODE_INHERITABLETHREADLOCAL

页面上获取用户信息

引入依赖

<dependency>
  <groupId>org.thymeleaf.extras</groupId>
  <artifactId>thymeleaf-extras-springsecurity5</artifactId>
  <version>3.0.4.RELEASE</version>
</dependency>

页面加入命名空间

<html lang="en" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">

页面中使用

<!--获取认证用户名-->
<ul>
  <li sec:authentication="principal.username"></li>
  <li sec:authentication="principal.authorities"></li>
  <li sec:authentication="principal.accountNonExpired"></li>
  <li sec:authentication="principal.accountNonLocked"></li>
  <li sec:authentication="principal.credentialsNonExpired"></li>
</ul>

到此这篇关于Spring Security获取用户认证信息的实现流程的文章就介绍到这了,更多相关Spring Security获取认证信息内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring Security中如何获取AuthenticationManager对象

    有时需要使用AuthenticationManager(以下简称Manager)对象,可是这个对象不是Bean,没有直接保存在Spring的Bean库中.那么如何获取Spring Security中的这个对象呢? 在Spring Security 5.7.0-M2之前,通常会扩展WebSecurityConfigurerAdapter(以下简称Adapter)类来自定义网络安全配置.Adapter类中有一个方法authenticationManager()可以提供Manager对象.但是从Spr

  • SpringSecurity报错authenticationManager must be spec的解决

    目录 有两个地方要改下 然后在过滤器里面显示的设置一下 顺便贴一下两个类的完整代码 过滤器 配置文件 在重写类UsernamePasswordAuthenticationFilter时抛出了这个异常,字面上理解是authenticationManager不明确,所以要显示的注入. 有两个地方要改下 首先要在配置文件重写authenticationManager @Bean @Override protected AuthenticationManager authenticationManage

  • SpringBoot整合Security权限控制登录首页

    目录 在 pom 文件中增加thymeleaf页面支持 application.yml 配置文件 login 页面 controller目录下跳转配置 UserController 在 pom 文件中增加thymeleaf页面支持 <!-- 引入页面模板 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thym

  • SpringBoot Security使用MySQL实现验证与权限管理

    目录 1. 创建用户表和虚拟凭据 2. 配置数据源属性 3. 声明弹簧安全性和MySQL JDBC驱动程序的依赖关系 4. 配置 JDBC 身份验证详细信息 5. 自定义登录验证过程 6. 登录页面 7. 测试登录和注销 结论 在本教程中,我将指导您如何编写代码,以使用具有基于表单的身份验证的Spring安全API来保护Spring Boot应用程序中的网页.用户详细信息存储在MySQL数据库中,并使用春季JDBC连接到数据库.我们将从本教程中的 ProductManager 项目开始,向现有的

  • Spring Security 登录时添加图形验证码实现实例

    目录 前言 验证码生成 加入验证码依赖 验证码配置 验证码接口 加入依赖 基于过滤器 编写自定义认证逻辑 测试 基于认证器 编写自定义认证逻辑 测试 前言 在前面的几篇文章中,登录时都是使用用户名 + 密码进行登录的,但是在实际项目当中,登录时,还需要输入图形验证码.那如何在 Spring Security 现有的认证体系中,加入自己的认证逻辑呢?这就是本文的内容,本文会介绍两种实现方案,一是基于过滤器实现:二是基于认证器实现. 验证码生成 既然需要输入图形验证码,那先来生成验证码吧. 加入验证

  • SpringBoot 整合Security权限控制的初步配置

    正文 在源码目录下新建 config 目录, 在该目录下新建 WebSecurityConfig 类文件 /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding co

  • Spring Security获取用户认证信息的实现流程

    目录 登录用户数据获取 SecurityContextHolder SecurityContextHolderStrategy 多线程情况下获取用户数据 页面上获取用户信息 登录用户数据获取 SecurityContextHolder ​ Spring Security 会将登录用户数据保存在 Session 中.但是,为了使用方便,Spring Security在此基础上还做了一些改进,其中最主要的一个变化就是线程绑定.当用户登录成功后,Spring Security 会将登录成功的用户信息保

  • spring security获取用户信息的实现代码

    前言 我们在使用spring security的时候可以通过好几种方法获取用户信息, 但是今天这篇文章介绍的是一个笔者觉得最优雅的实现; 借鉴现有的spring security controller自动注入参数的方法, 我们来进一步的实现更适合我们业务的用户信息获取方法; 思路 现在spring security会在controller自动注入Authentication/Userdetails等参数, 我们拿到这些对象之后还需要一些处理才可以拿到我们需要的信息, 例如用户ID; 那获取用户I

  • Spring security自定义用户认证流程详解

    1.自定义登录页面 (1)首先在static目录下面创建login.html 注意:springboot项目默认可以访问resources/resources,resources/staic,resources/public目录下面的静态文件 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录页面</titl

  • Spring Security使用数据库认证及用户密码加密和解密功能

    流程图: 1.接上一篇博客https://mp.csdn.net/console/editor/html/104576494,准备好环境. 2.spring-security.xml中的配置: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:security="

  • Springboot集成Spring Security实现JWT认证的步骤详解

    1 简介 Spring Security作为成熟且强大的安全框架,得到许多大厂的青睐.而作为前后端分离的SSO方案,JWT也在许多项目中应用.本文将介绍如何通过Spring Security实现JWT认证. 用户与服务器交互大概如下: 客户端获取JWT,一般通过POST方法把用户名/密码传给server: 服务端接收到客户端的请求后,会检验用户名/密码是否正确,如果正确则生成JWT并返回:不正确则返回错误: 客户端拿到JWT后,在有效期内都可以通过JWT来访问资源了,一般把JWT放在请求头:一次

  • Spring Security+JWT实现认证与授权的实现

    目录 一.登录校验流程 1.Spring Security 完整流程 2.Spring Security的默认登陆验证流程. 3. 整合JWT大致流程 前端响应类 JWT工具类 重写UserDetailsService的方法 重写登录接口 认证过滤器 退出登陆 授权基本流程 限制访问资源所需权限 封装权限信息 RBAC权限模型 自定义失败处理 认证:验证当前访问系统的是不是本系统的用户,并且要确认具体是哪个用户 授权:经过认证后判断当前用户是否有权限进行某个操作 一.登录校验流程 1.Sprin

  • Spring Security实现HTTP认证

    目录 前言 一.HTTP基本认证是什么? 二.HTTP基本认证流程 一.Spring Security使用HTTP基本认证 1.创建项目spring-security-http-auth 2.创建配置文件WebSecurityConfig 3.运行项目 二.Spring Security HTTP基本认证原理 三.HTTP摘要认证是什么? 四.Spring Security使用HTTP摘要认证流程? 运行项目 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安

  • 图解Spring Security 中用户是如何实现登录的

    1. 前言 欢迎阅读Spring Security 实战干货系列文章,在集成Spring Security安全框架的时候我们最先处理的可能就是根据我们项目的实际需要来定制注册登录了,尤其是Http登录认证.根据以前的相关文章介绍,Http登录认证由过滤器UsernamePasswordAuthenticationFilter 进行处理.我们只有把这个过滤器搞清楚才能做一些定制化.今天我们就简单分析它的源码和工作流程. 2. UsernamePasswordAuthenticationFilter

  • Springboot WebFlux集成Spring Security实现JWT认证的示例

    1 简介 在之前的文章<Springboot集成Spring Security实现JWT认证>讲解了如何在传统的Web项目中整合Spring Security和JWT,今天我们讲解如何在响应式WebFlux项目中整合.二者大体是相同的,主要区别在于Reactive WebFlux与传统Web的区别. 2 项目整合 引入必要的依赖: <dependency> <groupId>org.springframework.boot</groupId> <art

  • 微信获取用户地理位置信息的原理与步骤

    在微信公众服务号开发需求中经常有获取用户位置信息的功能,通过用户的位置信息,可以做一些地图导航,以及基于LBS的营销活动. 下面通过给大家介绍微信服务号获取用户位置信息的原理与步骤. 原理 1. 位置信息获取流程 2. 位置信息报文 <xml><ToUserName><![CDATA[gh_public_member_account]]></ToUserName> <FromUserName><![CDATA[oNEGGwGfl8f5xME

随机推荐