首页 > 编程语言 >java 令牌解析_SpringSecurity 原理解析【4】:令牌还原与Session String changeSessionId(); // 修改SessionId

java 令牌解析_SpringSecurity 原理解析【4】:令牌还原与Session String changeSessionId(); // 修改SessionId

时间:2023-11-29 19:22:18浏览次数:46  
标签:session 令牌 java String Session Cookie var1 解析

java 令牌解析_SpringSecurity 原理解析【4】:令牌还原与Session String changeSessionId(); // 修改SessionId

SpringSecurity 原理解析【4】:令牌还原与Session

Session:一般称为会话,不同环境中含义不同,在Spring Security中一个会话指:客户端从令牌认证请求到登出注销请求之间的过程。Web应用基本都是基于HTTP协议,而该协议是一个无状态协议,两个HTTP请求相互独立,无法识别对方,在Web应用特别是Spring Security等安全框架中,同一个客户端发出的多个请求,如果不能识别出,每个请求都需要认证过程,这对于每次请求都需要主动提供身份识别信息的客户端而言绝对是一个灾难。因此需要一个方案来解决这个问题:解决方案整体而言只有一个:就给相关的HTTP请求添加一个全局总线,将这些HTTP请求打上统一标志来说明这些请求都是来自同一个身份。而实现目前主流两种:Session 和 WebToken,前者为主流标准Web应用总线方案实现,标志打在Cookie或者URL上,后者为主流前后端分离Web应用总线方案实现,标志打在请求头上。

今天主要说明前者Session。在JavaEE中Session特指HttpSession,其规范是在服务器端定义且实现的:默认每个请求都会具有一个Session实例

public interface HttpSession {

// 创建时间

long getCreationTime();

boolean isNew();

// 唯一ID

String getId();

// 最近一次访问时间

long getLastAccessedTime();

//Servlet上下文

ServletContext getServletContext();

// 具有失效能力

void invalidate();

void setMaxInactiveInterval(int var1);

int getMaxInactiveInterval();

// 具有存储能力

Object getAttribute(String var1);

Enumeration getAttributeNames();

void setAttribute(String var1, Object var2);

void removeAttribute(String var1);

}

此时可以这么理解Session:是一个具有唯一标识且可控生命周期的存储结构,底层一般为:ConcurrentMap。

Session追踪

会话追踪: SessionTracking,意思是追踪Session来源,也就是从哪里开始查找总线标记,默认为Cookie和URL,@since Servlet 3.0可配置

public enum SessionTrackingMode {

COOKIE, URL, SSL

}

Cookie就是将sessionId写入Cookie,URL则是在重定向时将sessionId写入URL。而解析Cookie或者URL是在HttpServer内部完成的,例如:tomcat、undertow。所以一般看不到Session构建的细节(不同服务器实现不一样),例如Tomcat服务器在构建Request时在CoyoteAdapter#postParseRequest,解析SessionId顺序为URL --> Cookie --> SSL ,且Cookie优先级最高,URL次之。

虽然不用知道如何解析Session,但是JavaEE给出构建入口和构建要求:HttpServletRequest#getSession,默认情况下session的构建交给HttpServer完成,但对于分布式应用,可以由Spring Session模块接手Session的生命周期。

注意如果会话追踪ID丢失,则会导致Session==null,后续所有依赖了Session存储的功能就会失败:例如:CsrfFilter

// 主动确定返回的Session是否需要重新构建

HttpSession getSession(boolean var1);

// 获取当前请求的Session实例,如果不存在则构建

HttpSession getSession();

// 修改SessionId

String changeSessionId();

// Session有效性:是否存活

boolean isRequestedSessionIdValid();

// Session构建来源:是否从Cookie中解析

boolean isRequestedSessionIdFromCookie();

// Session构建来源:是否从URL中解析

boolean isRequestedSessionIdFromURL();

在Spring Security中在服务端完善令牌之后,可以从上篇文章图示中看到:令牌完整之后进行了Session、Context和Cookie管理.

Session的处理是通过SessionAuthenticationStrategy来执行的。默认是组合(Composite)策略,内置:ChangeSessionIdAuthenticationStrategy,复用现有Session,修改其唯一标识。

CsrfAuthenticationStrategy (org.springframework.security.web.csrf)

ConcurrentSessionControlAuthenticationStrategy (org.springframework.security.web.authentication.session)

RegisterSessionAuthenticationStrategy (org.springframework.security.web.authentication.session)

CompositeSessionAuthenticationStrategy (org.springframework.security.web.authentication.session)

NullAuthenticatedSessionStrategy (org.springframework.security.web.authentication.session)

AbstractSessionFixationProtectionStrategy (org.springframework.security.web.authentication.session)

ChangeSessionIdAuthenticationStrategy (org.springframework.security.web.authentication.session)

SessionFixationProtectionStrategy (org.springframework.security.web.authentication.session)

在Session做了案底之后就可以在后续请求中获取到并还原了

令牌还原

在Spring Security中有一个优先级很高的过滤器:SecurityContextPersistenceFilter:上下文持久化过滤器,还记得在FilterSecurityInterceptor中获取服务端完整令牌就是从SecurityContext中获取的吗?

SecurityContext contextBeforeChainExecution = securityContextRepository.loadContext(holder);

这里有个SecurityContextRepository,安全上下文存储库,默认是HttpSessionSecurityContextRepository,也就是从HttpSession中获取到的上下文。而HttpSession则在会话追踪中已经还原了。

// -------------------------------- session 存储 ------------------------------

// 先获取到请求中的Session

HttpSession httpSession = request.getSession(false);

// 从Session中获取SecurityContext

SecurityContext context = readSecurityContextFromSession(httpSession);

// context 就是从ConcurrentMap中 key="SPRING_SECURITY_CONTEXT"获取

Object contextFromSession = httpSession.getAttribute(springSecurityContextKey);

// -------------------------------- context 存储 ------------------------------

SecurityContextHolder.setContext(context);

到这里,Session的整体流程就清晰明了了,整体图示如下:

5fa19d39bd6451f11077ff3ade973d4e.png

Session配置

Session细节交给了服务器去设置,但是Session的配置接口是规范好的:

public interface SessionCookieConfig {

// 名称配置:常见为:JSESSIONID

void setName(String var1);

String getName();

// 设置能携带Cookie的请求域名

// 后缀匹配,设置格式:点+域名

void setDomain(String var1);

String getDomain();

// 设置能携带Cookie的请求路径

// 前缀匹配:紧邻域名之后的部分URL,默认:/

void setPath(String var1);

String getPath();

// 设置额外备注

void setComment(String var1);

String getComment();

// 是否允许客户端操作Cookie

void setHttpOnly(boolean var1);

boolean isHttpOnly();

// 设置能携带Cookie的请求方式:

// ture: https,false: http、https

void setSecure(boolean var1);

boolean isSecure();

// 有效期配置,默认-1,常见:3600

void setMaxAge(int var1);

int getMaxAge();

}

Spring对Server的Session有对应的配置类,在容器启动是会配置到Servlet中。示例:

server.servlet.context-path= /ctx

server.servlet.session.cookie.name= Authorization

server.servlet.session.cookie.path= /ctx/cookie/

server.servlet.session.cookie.max-age=3600

server.servlet.session.cookie.http-only=true

server.servlet.session.cookie.secure=false

server.servlet.session.cookie.comment=new cookie name

浏览器:

Set-Cookie: Authorization=_xkjjuKHOrOLbS3KRlUmOrRYYn-Z9oa-cLCLWS54; Version=1; Path=/ctx/cookie/; HttpOnly; Max-Age=3600; Expires=Mon, 26-Oct-2020 02:25:57 GMT; Comment="new cookie name"

后续携带Cookie

Cookie: Authorization=dhiWDzOksYItVwcqIZAew0YQqtA8BI9DZIVUXWjK

注意:Cookie的path默认为:"/",意味着任何页面如果携带Cookie,将是同一个。如果配置为其他值,一定要保证Spring Security的认证路径能匹配到来传输Cookie。配置格式应该为:"contextPath/匹配值路径/",表示匹配路径及其子路径都会携带匹配路径请求是产生的Cookie。

原文链接:https://blog.csdn.net/weixin_39930748/article/details/115074842?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-5-115074842-blog-126679312.235^v38^pc_relevant_sort_base1&spm=1001.2101.3001.4242.4&utm_relevant_index=6

标签:session,令牌,java,String,Session,Cookie,var1,解析
From: https://www.cnblogs.com/sunny3158/p/17865655.html

相关文章

  • java基础学习:random随机数,random案例
    1.Random使用步骤:  packagecom.itheima.Random;importjava.util.Random;publicclassRandom1{publicstaticvoidmain(String[]args){Randomrandom=newRandom();for(inti=1;i<=10;i++){intdata=random.nextInt(1......
  • 学了SpringBoot的令牌
    packagecom.itheima.bigeventadmin.utils;importcom.auth0.jwt.JWT;importcom.auth0.jwt.algorithms.Algorithm;importjava.util.Date;importjava.util.Map;publicclassJwtUtil{privatestaticfinalStringKEY="itheima";//接收业......
  • JAVA的swap实现
    JAVA的swap实现JAVA不能操作地址,所以不能像CPP那样方便地实现对基本数据类型的swap。java中的基本数据类型传递属于引用传递,并不会像c/c++实现指针传递;通过包装类对象配合反射可以实现数据的交换。只能通过以下几种方式。通过数组对象交换publicclassTestSwap{ publi......
  • Java 8 仍被广泛使用,占比 50%
    调查中,更多的开发人员选择在生产中使用Java17,而不是Java11。Docker逐渐成为打包Web应用程序的首选,且Spring和SpringBoot的使用率遥遥领先。具体而言,开发者最常使用的 Java版本是 Java8,占比高达 50%;其次分别是 Java17(45%)、Java11(38%)以及 Java20(11%......
  • NOIP2000提高组真题解析
    NOIP2000提高组真题解析第一题进制转换题目链接解析首先,我们知道对于10进制数x转2进制数,使用的算法是:求出x%2令x=x/2不断执行1,2,直至x为0,然后倒序输出步骤1的结果。一般可以用数组存步骤1的结果倒序输出或者使用dfs回溯回来再输出。对于负数的情况,比如\(-7=1*(-2)^3......
  • 学习笔记1 :Java基础
    1、JVM(1)Java虚拟机:是运行所有Java程序的抽象计算机,是Java语言的运行环境。(2)JVM包括:一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域(3)跨平台:JVM在执行字节码时,把字节码解释成具体平台上的机器指令执行。一套代码,一次编译,多平台运行。但是,不同平台需要不......
  • java基础学习:跳转关键字:break,continue
    1.总览:break:跳出并结束当前所在循环的执行continue:用于跳出当前循环的当次执行,直接进入循环的下一次执行 packagecom.itheima.BreakAndContinue;publicclassBreakAndContine1{publicstaticvoidmain(String[]args){for(inti=1;i<=5;i++){......
  • java基础学习:死循环,循环嵌套
    1.死循环:写法 packagecom.itheima.loop;publicclassEndLessLoop{publicstaticvoidmain(String[]args){//掌握死循环写法//for(;;){//System.out.println("ss");//}//while(true){//System......
  • Java集合框架之:LinkedList的常见方法使用
    ✨前言✨本篇文章主要介绍JavaLinkedList的使用方法教程及示例代码......
  • java基础学习:do-while循环
    1. packagecom.itheima.loop;publicclassDowhile1{publicstaticvoidmain(String[]args){inti=0;do{System.out.println("1");i++;}while(i<3);}} ......