sa-token/sa-token-doc/fun/sa-token-context.md
2024-04-11 07:59:33 +08:00

7.5 KiB
Raw Blame History

自定义 SaTokenContext 指南

目前 Sa-Token 仅对 SpringBoot、SpringMVC、WebFlux、Solon 等部分 Web 框架制作了 Starter 集成包, 如果我们使用的 Web 框架不在上述列表之中,则需要自定义 SaTokenContext 接口的实现完成整合工作。


1、SaTokenContext是什么为什么要实现 SaTokenContext 接口?

在鉴权中,必不可少的步骤就是从 HttpServletRequest 中读取 Token然而并不是所有框架都具有 HttpServletRequest 对象,例如在 WebFlux 中,只有 ServerHttpRequest 在一些其它Web框架中可能连 Request 的概念都没有。

那么Sa-Token 如何只用一套代码就对接到所有 Web 框架呢?

解决这个问题的关键就在于 SaTokenContext 接口,此接口的作用是屏蔽掉不同 Web 框架之间的差异提供统一的调用API

sa-token-context

SaTokenContext只是一个接口没有工作能力这也就意味着 SaTokenContext 接口的实现是必须的。 那么疑问来了,我们之前在 SpringBoot 中引用 Sa-Token 时为什么可以直接使用呢?

其实原理很简单,sa-token-spring-boot-starter集成包中已经内置了SaTokenContext的实现:SaTokenContextForSpring 并且根据 Spring 的自动注入特性,在项目启动时注入到 Sa-Token 中,做到“开箱即用”。

那么如果我们使用不是 Spring 框架,是不是就必须得手动实现 SaTokenContext 接口答案是肯定的脱离Spring 环境后,我们就不能再使用sa-token-spring-boot-starter集成包了, 此时我们只能引入 sa-token-core 核心包,然后手动实现 SaTokenContext 接口。

不过不用怕,这个工作很简单,只要跟着下面的文档一步步来,你就可以将 Sa-Token 对接到任意Web框架中。

2、实现 Model 接口

我们先来观察一下 SaTokenContext 接口的签名:

/**
 * Sa-Token 上下文处理器
 */
public interface SaTokenContext {

	/**
	 * 获取当前请求的 [Request] 对象
	 */
	public SaRequest getRequest();

	/**
	 * 获取当前请求的 [Response] 对象
	 */
	public SaResponse getResponse();

	/**
	 * 获取当前请求的 [存储器] 对象 
	 */
	public SaStorage getStorage();

	/**
	 * 校验指定路由匹配符是否可以匹配成功指定路径 
	 */
	public boolean matchPath(String pattern, String path);

}

你可能对 SaRequest 比较疑惑,这个对象是干什么用的?正如每个 Web 框架都有 Request 概念的抽象Sa-Token 也封装了 RequestResponseStorage三者的抽象:

  • Request:请求对象,携带着一次请求的所有参数数据。参考:SaRequest.java
  • Response:响应对象,携带着对客户端一次响应的所有数据。参考:SaResponse.java
  • Storage:请求上下文对象,提供 [一次请求范围内] 的上下文数据读写。参考:SaStorage.java

因此,在实现 SaTokenContext 之前,你必须先实现这三个 Model 接口。

先别着急动手,如果你的 Web 框架是基于 Servlet 规范开发的,那么 Sa-Token 已经为你封装好了三个 Model 接口的实现,你要做的就是引入 sa-token-servlet包即可:

<!-- Sa-Token 权限认证ServletAPI 集成包) -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-servlet</artifactId>
    <version>${sa.top.version}</version>
</dependency>
// Sa-Token 权限认证ServletAPI 集成包)
implementation 'cn.dev33:sa-token-servlet:${sa.top.version}'

如果你的 Web 框架不是基于 Servlet 规范,那么你就需要手动实现这三个 Model 接口,我们可以参考 sa-token-servlet 是怎样实现的: SaRequestForServlet.javaSaResponseForServlet.javaSaStorageForServlet.java

3、实现 SaTokenContext 接口

接下来我们奔入主题,提供 SaTokenContext 接口的实现,同样我们可以参考 Spring 集成包是怎样实现的:

/**
 * Sa-Token 上下文处理器 [ SpringMVC版本实现 ] 
 */
public class SaTokenContextForSpring implements SaTokenContext {

	/**
	 * 获取当前请求的Request对象
	 */
	@Override
	public SaRequest getRequest() {
		return new SaRequestForServlet(SpringMVCUtil.getRequest());
	}

	/**
	 * 获取当前请求的Response对象
	 */
	@Override
	public SaResponse getResponse() {
		return new SaResponseForServlet(SpringMVCUtil.getResponse());
	}

	/**
	 * 获取当前请求的 [存储器] 对象 
	 */
	@Override
	public SaStorage getStorage() {
		return new SaStorageForServlet(SpringMVCUtil.getRequest());
	}
	
	/**
	 * 校验指定路由匹配符是否可以匹配成功指定路径 
	 */
	@Override
	public boolean matchPath(String pattern, String path) {
		return SaPathMatcherHolder.getPathMatcher().match(pattern, path);
	}

}

详细参考: SaTokenContextForSpring.java

4、将自定义实现注入到 Sa-Token 框架中

有了 SaTokenContext 接口的实现,我们还需要将这个实现类注入到 Sa-Token 之中,伪代码参考如下:

/**
 * 程序启动类
 */
public class Application {

	public static void main(String[] args) {
		// 框架启动
		XxxApplication.run(xxx);
		
		// 将自定义的 SaTokenContext 实现类注入到框架中 
		SaTokenContext saTokenContext = new SaTokenContextForXxx();
		SaManager.setSaTokenContext(saTokenContext);
	}
	
}

如果你使用的框架带有自动注入特性,那就更简单了,参考 Spring 集成包的 Bean 注入流程: 注册Bean注入Bean

5、启动项目

启动项目,尝试打印一下 SaManager.getSaTokenContext() 对象,如果输出的是你的自定义实现类,那就证明你已经自定义 SaTokenContext 成功了, 快来体验一下 Sa-Token 的各种功能吧。