为什么 login 后 StpUtil.getTokenInfo() 未false
Closed this issue · 5 comments
inrhor commented
对以下问题有疑问:
- 一个从未登录过的用户没有token情况下去请求登录接口
- 然后我在apifox测试请求
相关代码:
// 第一步:比对前端提交的账号名称、密码
if ("zhang" == name/* && "123456" == pwd*/) {
// 第二步:根据账号id,进行登录
StpUtil.login(10001)
val tokenInfo = StpUtil.getTokenInfo()
// Step 3: 返回 token 信息到前端
return SaResult.data(tokenInfo)
}
return SaResult.error("登录失败")
apifox返回:
{
"code": 200,
"msg": "ok",
"data": {
"tokenName": "satoken",
"isLogin": false,
"loginType": "login",
"tokenTimeout": -2,
"sessionTimeout": -2,
"tokenSessionTimeout": -2,
"tokenActiveTimeout": -1
}
}
日志输出:
SA [INFO] -->: 账号 10001 登录成功 (loginType=login), 会话凭证 token=511971cd-8909-4ae8-a80d-52fc1147850d
POST - /salogin/test - 200 OK - 1.6291ms
最后,我没法从StpUtil.getTokenInfo()获取token交给前端
我用其他冷门框架+javalin搭配,没有使用Spring,自定义实现Context,写入SaConfig配置
不知道漏了什么步骤
click33 commented
自定义的实现贴出来看看
inrhor commented
自定义的实现贴出来看看
import cn.dev33.satoken.context.SaTokenContext
import cn.dev33.satoken.context.model.SaRequest
import cn.dev33.satoken.context.model.SaResponse
import cn.dev33.satoken.context.model.SaStorage
import io.javalin.http.Context
class SaTokenContextImpl(val context: Context): SaTokenContext {
override fun getRequest(): SaRequest {
return SaRequestImpl(context)
}
override fun getResponse(): SaResponse {
return SaResponseImpl(context)
}
override fun getStorage(): SaStorage {
return SaStorageImpl(context)
}
// 实现 matchPath,判断路径是否匹配
override fun matchPath(pattern: String?, path: String?): Boolean {
if (pattern == null || path == null) return false
// 使用 Sa-Token 的路径匹配规则,或自定义路径匹配逻辑
return path.matches(pattern.toRegex())
}
}
import cn.dev33.satoken.context.model.SaRequest
import io.javalin.http.Context
class SaRequestImpl(val context: Context): SaRequest {
override fun getSource(): Context {
return context
}
override fun getParam(name: String): String? {
return context.queryParam(name)
}
override fun getParamNames(): MutableList<String> {
return context.queryParamMap().keys.toMutableList()
}
override fun getParamMap(): MutableMap<String, String> {
// 将 Javalin 的 Map<String, List<String>> 转换为 Sa-Token 所需的 Map<String, String>
return context.queryParamMap().mapValues { it.value.firstOrNull().orEmpty() }.toMutableMap()
}
override fun getHeader(name: String): String? {
return context.header(name) ?: ""
}
override fun getCookieValue(name: String): String? {
return context.cookie(name) ?: ""
}
override fun getCookieFirstValue(name: String): String? {
return context.cookie(name)?.split(";")?.firstOrNull() ?: ""
}
override fun getCookieLastValue(name: String): String? {
return context.cookie(name)?.split(";")?.lastOrNull() ?: ""
}
override fun getRequestPath(): String {
return context.matchedPath()
}
override fun getUrl(): String {
return context.url()
}
override fun getMethod(): String {
// 获取实际的 HTTP 方法,或者使用 X-HTTP-Method-Override 头的值
val handlerType = context.method()
return handlerType.name // 转换 HandlerType 为字符串
}
override fun forward(path: String) {
// 执行重定向操作
context.redirect(path)
}
}
import cn.dev33.satoken.context.model.SaStorage
import io.javalin.http.Context
class SaStorageImpl(private val context: Context) : SaStorage {
// 创建一个存储会话数据的映射
private val storageMap: MutableMap<String, Any?> = mutableMapOf()
// 获取存储中某个键的值
override fun get(key: String): Any? {
return storageMap[key]
}
// 设置存储中的某个键值对
override fun set(key: String?, value: Any?): SaStorage {
if (key != null) {
storageMap[key] = value
}
return this
}
// 删除存储中的某个键值对
override fun delete(key: String?): SaStorage {
if (key != null) {
storageMap.remove(key)
}
return this
}
// 返回存储的源对象,在这里我们可以直接返回 Javalin 的 Context
override fun getSource(): Any {
return context
}
}
import cn.dev33.satoken.context.model.SaResponse
import io.javalin.http.Context
class SaResponseImpl(private val context: Context) : SaResponse {
// 返回 Javalin 的 Context 作为源对象,供 Sa-Token 使用
override fun getSource(): Any {
return context
}
// 设置 HTTP 响应状态码
override fun setStatus(statusCode: Int): SaResponse {
context.status(statusCode)
return this
}
// 设置 HTTP 响应头(覆盖现有值)
override fun setHeader(name: String?, value: String?): SaResponse {
if (name != null && value != null) {
context.header(name, value)
}
return this
}
// 添加 HTTP 响应头(不会覆盖已有值)
override fun addHeader(name: String?, value: String?): SaResponse {
if (name != null && value != null) {
context.header(name, context.header(name) + ", " + value)
}
return this
}
// 执行重定向到指定 URL
override fun redirect(location: String?): Any {
return context.redirect(location)
}
}
server.before {
val saTokenContext = SaTokenContextImpl(it)
SaManager.setSaTokenContext(saTokenContext)
}
click33 commented
没看出来哪有问题,不过猜测可能是 SaStorage 的实现有点问题,导致登录时没有把token成功保存到上下文,导致后续再获取也没有获取到
inrhor commented
感谢定位问题,确实SaStorage实现有错
inrhor commented
我又重新打开了,因为测试登录后,请求查询是否登录时,结果为false
@RouterNode("/isLogin")
fun isLogin(): SaResult {
return SaResult.ok("是否登录:${StpUtil.isLogin()}")
}
apifox都测试过cookie和bearer token,均请求为false。(登录请求后还没有注销)
已解决,请求头要对应tokenName去写Bearer token