mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-08-24 16:18:38 +08:00
Merge branch 'dev' of https://gitee.com/dromara/sa-token into dev
This commit is contained in:
commit
a0891170d7
23
sa-token-demo/sa-token-demo-remember-me/page_project/.gitignore
vendored
Normal file
23
sa-token-demo/sa-token-demo-remember-me/page_project/.gitignore
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# vite创建项目时自动生成的git忽略配置文件
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
@ -0,0 +1,11 @@
|
|||||||
|
# Vue 3 + Vite
|
||||||
|
|
||||||
|
[Node下载地址](https://nodejs.org/zh-cn/)
|
||||||
|
|
||||||
|
安装最新版本Node环境, 然后执行如下命令开启开发服务:
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
[cookie/sessionstorage/localstorage三者的区别](https://blog.csdn.net/weixin_45541388/article/details/125367823)
|
@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>记住我模式Demo页面</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"name": "page_project",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.3.4",
|
||||||
|
"element-plus": "^2.2.33",
|
||||||
|
"qs": "^6.11.0",
|
||||||
|
"vue": "^3.2.45",
|
||||||
|
"vue-axios": "^3.5.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-vue": "^4.0.0",
|
||||||
|
"vite": "^4.1.0"
|
||||||
|
}
|
||||||
|
}
|
160
sa-token-demo/sa-token-demo-remember-me/page_project/src/App.vue
Normal file
160
sa-token-demo/sa-token-demo-remember-me/page_project/src/App.vue
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mainLayoutClass">
|
||||||
|
<div class="loginClass">
|
||||||
|
<div class="titleClass">
|
||||||
|
账户登录
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-input v-model="name" placeholder="账号" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-input v-model="passwd" placeholder="密码" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>
|
||||||
|
<el-switch v-model="rememberMe" />
|
||||||
|
</span>
|
||||||
|
<span class="tipInfoClass" @click="rememberMe = !rememberMe">记住我</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-button type="primary" style="width: 100%;" @click="loginFun">登录</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stateClass">
|
||||||
|
<div class="titleClass">当前登录状态:</div>
|
||||||
|
<div class="titleClass">{{ loginState }}</div>
|
||||||
|
<div>
|
||||||
|
<el-button type="primary" style="width: 100%;" @click="checkLoginStateFun">刷新登录状态</el-button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-button type="danger" style="width: 100%;" @click="logoutFun">退出</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mounted () {
|
||||||
|
if (localStorage.getItem('rememberMe') === 'true') {
|
||||||
|
this.rememberMe = true
|
||||||
|
}
|
||||||
|
this.checkLoginStateFun()
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
name: 'zhang',
|
||||||
|
passwd: '123456',
|
||||||
|
rememberMe: false,
|
||||||
|
loginState: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
loginFun () {
|
||||||
|
this.axios.post('/back/user/login', this.$f({
|
||||||
|
name: this.name,
|
||||||
|
pwd: this.passwd,
|
||||||
|
remember: this.rememberMe
|
||||||
|
})).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.loginState = true
|
||||||
|
const { tokenName, tokenValue } = res.data
|
||||||
|
localStorage.setItem('tokenName', tokenName)
|
||||||
|
if (this.rememberMe) {
|
||||||
|
localStorage.setItem('tokenValue', tokenValue)
|
||||||
|
} else {
|
||||||
|
sessionStorage.setItem('tokenValue', tokenValue)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.$message.error('网络异常')
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
this.$message.error('无法访问后台服务')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
checkLoginStateFun () {
|
||||||
|
let tokenName, tokenValue
|
||||||
|
tokenName = localStorage.getItem('tokenName')
|
||||||
|
if (this.rememberMe) {
|
||||||
|
tokenValue = localStorage.getItem('tokenValue')
|
||||||
|
} else {
|
||||||
|
tokenValue = sessionStorage.getItem('tokenValue')
|
||||||
|
}
|
||||||
|
const param = {}
|
||||||
|
param[tokenName] = tokenValue
|
||||||
|
this.axios.post('/back/user/state', this.$f(param))
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.loginState = res.data.data
|
||||||
|
} else {
|
||||||
|
this.$message.error('网络异常')
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
this.$message.error('无法访问后台服务')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
logoutFun () {
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// 重复的部分可以写到外部js统一封装或通过axios的拦截器添加token参数, 这里只做演示
|
||||||
|
let tokenName, tokenValue
|
||||||
|
tokenName = localStorage.getItem('tokenName')
|
||||||
|
if (this.rememberMe) {
|
||||||
|
tokenValue = localStorage.getItem('tokenValue')
|
||||||
|
} else {
|
||||||
|
tokenValue = sessionStorage.getItem('tokenValue')
|
||||||
|
}
|
||||||
|
const param = {}
|
||||||
|
param[tokenName] = tokenValue
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
this.axios.post('/back/user/logout', this.$f(param))
|
||||||
|
.then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.loginState = res.data.data
|
||||||
|
} else {
|
||||||
|
this.$message.error('网络异常')
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
this.$message.error('无法访问后台服务')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
rememberMe (newValue, oldValue) {
|
||||||
|
// 打开不同页面时使 记住我 的状态保持一致
|
||||||
|
localStorage.setItem('rememberMe', newValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.mainLayoutClass{
|
||||||
|
padding: 0 25%;
|
||||||
|
padding-top: 20vh;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.loginClass{
|
||||||
|
min-width: 300px;
|
||||||
|
height: 210px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.titleClass{
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.tipInfoClass{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.stateClass{
|
||||||
|
min-width: 300px;
|
||||||
|
height: 200px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,20 @@
|
|||||||
|
import { createApp } from 'vue'
|
||||||
|
import App from './App.vue'
|
||||||
|
import axios from 'axios' // 请求发送接收工具
|
||||||
|
import VueAxios from 'vue-axios' // vue封装axios
|
||||||
|
import qs from 'qs' // axios请求参数类型封装
|
||||||
|
import ElementPlus from 'element-plus' // elementUI for vue3
|
||||||
|
import 'element-plus/dist/index.css' // 加载elementUI样式
|
||||||
|
import zhCn from 'element-plus/es/locale/lang/zh-cn' // 引入中文本地化组件
|
||||||
|
|
||||||
|
|
||||||
|
const app = createApp(App)
|
||||||
|
|
||||||
|
// vue组件内通过 this.$f() 来调用
|
||||||
|
app.config.globalProperties.$f = (params) => {
|
||||||
|
return qs.stringify(params)
|
||||||
|
}
|
||||||
|
|
||||||
|
app.use(VueAxios, axios)
|
||||||
|
.use(ElementPlus, { locale: zhCn })
|
||||||
|
.mount('#app')
|
@ -0,0 +1,17 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
|
||||||
|
// 开启代理服务
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [vue()],
|
||||||
|
server: {
|
||||||
|
port: 5173,
|
||||||
|
host: true,
|
||||||
|
proxy: {
|
||||||
|
'^/back/.*$': {
|
||||||
|
target: 'http://localhost:80'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
@ -0,0 +1,48 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>cn.dev33</groupId>
|
||||||
|
<artifactId>remember_me</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<!-- SpringBoot -->
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.5.14</version>
|
||||||
|
<relativePath/>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<sa-token.version>1.34.0</sa-token.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- SpringBoot Web依赖 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Sa-Token 权限认证, 在线文档:https://sa-token.cc/ -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.dev33</groupId>
|
||||||
|
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||||
|
<version>${sa-token.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Sa-Token 插件:整合redis (使用jackson序列化方式) -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.dev33</groupId>
|
||||||
|
<artifactId>sa-token-dao-redis-jackson</artifactId>
|
||||||
|
<version>${sa-token.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-pool2</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -0,0 +1,11 @@
|
|||||||
|
package cc.sa_token;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class RememberMeApplication {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(RememberMeApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package cc.sa_token.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import cn.dev33.satoken.util.SaResult;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/back/user")
|
||||||
|
public class UserLoginController {
|
||||||
|
|
||||||
|
@RequestMapping("/login")
|
||||||
|
public SaResult doLogin(String name, String pwd, Boolean remember) {
|
||||||
|
if("zhang".equals(name) && "123456".equals(pwd)) {
|
||||||
|
StpUtil.login(10001, remember);
|
||||||
|
SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
|
||||||
|
return SaResult.ok()
|
||||||
|
.set("tokenName", tokenInfo.getTokenName())
|
||||||
|
.set("tokenValue", tokenInfo.getTokenValue());
|
||||||
|
} else {
|
||||||
|
return SaResult.error("登录失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/state")
|
||||||
|
public SaResult checkNowLoginState() {
|
||||||
|
return SaResult.ok().setData(StpUtil.isLogin());
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/logout")
|
||||||
|
public SaResult doLogout() {
|
||||||
|
StpUtil.logout();
|
||||||
|
return SaResult.ok().setData(StpUtil.isLogin());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
# 端口
|
||||||
|
server:
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
# sa-token配置
|
||||||
|
sa-token:
|
||||||
|
# token名称 (同时也是cookie名称)
|
||||||
|
token-name: satoken
|
||||||
|
# token有效期,单位s 默认30天, -1代表永不过期
|
||||||
|
timeout: 2592000
|
||||||
|
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
|
||||||
|
activity-timeout: -1
|
||||||
|
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||||
|
is-concurrent: true
|
||||||
|
# 禁止写入cookie
|
||||||
|
is-read-cookie: false
|
||||||
|
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
|
||||||
|
is-share: false
|
||||||
|
# token风格
|
||||||
|
token-style: uuid
|
||||||
|
# 是否输出操作日志
|
||||||
|
is-log: false
|
||||||
|
|
||||||
|
spring:
|
||||||
|
# redis配置
|
||||||
|
redis:
|
||||||
|
# Redis数据库索引(默认为0)
|
||||||
|
database: 0
|
||||||
|
# Redis服务器地址
|
||||||
|
host: 127.0.0.1
|
||||||
|
# Redis服务器连接端口
|
||||||
|
port: 6379
|
||||||
|
# Redis服务器连接密码(默认为空)
|
||||||
|
password:
|
||||||
|
# 连接超时时间
|
||||||
|
timeout: 10s
|
||||||
|
lettuce:
|
||||||
|
pool:
|
||||||
|
# 连接池最大连接数
|
||||||
|
max-active: 200
|
||||||
|
# 连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||||
|
max-wait: -1ms
|
||||||
|
# 连接池中的最大空闲连接
|
||||||
|
max-idle: 10
|
||||||
|
# 连接池中的最小空闲连接
|
||||||
|
min-idle: 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
|||||||
<!-- 定义 Sa-Token 版本号 -->
|
<!-- 定义 Sa-Token 版本号 -->
|
||||||
<properties>
|
<properties>
|
||||||
<sa-token.version>1.34.0</sa-token.version>
|
<sa-token.version>1.34.0</sa-token.version>
|
||||||
<solon.version>1.12.4</solon.version>
|
<solon.version>2.2.1</solon.version>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
@ -2,6 +2,7 @@ package com.pj;
|
|||||||
|
|
||||||
|
|
||||||
import org.noear.solon.Solon;
|
import org.noear.solon.Solon;
|
||||||
|
import org.noear.solon.annotation.SolonMain;
|
||||||
|
|
||||||
import cn.dev33.satoken.SaManager;
|
import cn.dev33.satoken.SaManager;
|
||||||
|
|
||||||
@ -10,6 +11,7 @@ import cn.dev33.satoken.SaManager;
|
|||||||
* @author noear
|
* @author noear
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@SolonMain
|
||||||
public class SaTokenDemoApp {
|
public class SaTokenDemoApp {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<!-- 定义 Sa-Token 版本号 -->
|
<!-- 定义 Sa-Token 版本号 -->
|
||||||
<properties>
|
<properties>
|
||||||
<sa-token.version>1.34.0</sa-token.version>
|
<sa-token.version>1.34.0</sa-token.version>
|
||||||
<solon.version>1.12.4</solon.version>
|
<solon.version>2.2.1</solon.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -2,7 +2,9 @@ package com.pj;
|
|||||||
|
|
||||||
|
|
||||||
import org.noear.solon.Solon;
|
import org.noear.solon.Solon;
|
||||||
|
import org.noear.solon.annotation.SolonMain;
|
||||||
|
|
||||||
|
@SolonMain
|
||||||
public class SaSsoServerApp {
|
public class SaSsoServerApp {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
@ -23,9 +23,9 @@
|
|||||||
<servlet-api.version>3.1.0</servlet-api.version>
|
<servlet-api.version>3.1.0</servlet-api.version>
|
||||||
<jakarta-servlet-api.version>6.0.0</jakarta-servlet-api.version>
|
<jakarta-servlet-api.version>6.0.0</jakarta-servlet-api.version>
|
||||||
<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
|
<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
|
||||||
<solon.version>1.12.4</solon.version>
|
<solon.version>2.2.1</solon.version>
|
||||||
<noear-redisx.version>1.4.5</noear-redisx.version>
|
<noear-redisx.version>1.4.5</noear-redisx.version>
|
||||||
<noear-snack3.version>3.2.50</noear-snack3.version>
|
<noear-snack3.version>3.2.54</noear-snack3.version>
|
||||||
<jfinal.version>4.9.17</jfinal.version>
|
<jfinal.version>4.9.17</jfinal.version>
|
||||||
<jboot.version>3.14.4</jboot.version>
|
<jboot.version>3.14.4</jboot.version>
|
||||||
<commons-pool2.version>2.5.0</commons-pool2.version>
|
<commons-pool2.version>2.5.0</commons-pool2.version>
|
||||||
|
@ -80,6 +80,12 @@ session.set("name", "张三");
|
|||||||
|
|
||||||
只要两个自定义Session的Id一致,它们就是同一个Session
|
只要两个自定义Session的Id一致,它们就是同一个Session
|
||||||
|
|
||||||
|
Custom-Session的会话有效期默认使用`SaManager.getConfig().getTimeout()`, 如果需要修改会话有效期, 可以在创建之后, 使用对象方法修改
|
||||||
|
|
||||||
|
``` java
|
||||||
|
session.updateTimeout(1000); // 参数说明和全局有效期保持一致
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### 4、Session模型结构图
|
### 4、Session模型结构图
|
||||||
|
|
||||||
|
@ -95,7 +95,6 @@ StpUtil.stpLogic.updateLastActivityToNow(tokenValue);
|
|||||||
| StpUtil.getLoginIdAsLong() |
|
| StpUtil.getLoginIdAsLong() |
|
||||||
|---|
|
|---|
|
||||||
| StpUtil.getSession() |
|
| StpUtil.getSession() |
|
||||||
| StpUtil.getSession() |
|
|
||||||
| StpUtil.getTokenSession() |
|
| StpUtil.getTokenSession() |
|
||||||
|---|
|
|---|
|
||||||
| StpUtil.getRoleList() |
|
| StpUtil.getRoleList() |
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# 框架博客
|
# 框架博客
|
||||||
|
|
||||||
> 此页面收集 Sa-Token 相关技术文章,欢迎大家投稿(不限平台,按照发表日期倒叙),
|
> 此页面收集 Sa-Token 相关技术文章,欢迎大家投稿(不限平台,按照发表日期倒序),
|
||||||
> [投稿链接](https://wj.qq.com/s2/10596458/aa96/)
|
> [投稿链接](https://wj.qq.com/s2/10596458/aa96/)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -45,7 +45,6 @@ SaFoxUtil.getRandomString(8); // 生成指定长度的随机字符串
|
|||||||
SaFoxUtil.isEmpty(str); // 指定字符串是否为null或者空字符串
|
SaFoxUtil.isEmpty(str); // 指定字符串是否为null或者空字符串
|
||||||
SaFoxUtil.isNotEmpty(str); // 指定字符串是否不是null或者空字符串
|
SaFoxUtil.isNotEmpty(str); // 指定字符串是否不是null或者空字符串
|
||||||
SaFoxUtil.equals(a, b); // 比较两个对象是否相等
|
SaFoxUtil.equals(a, b); // 比较两个对象是否相等
|
||||||
SaFoxUtil.equals(a, b); // 比较两个对象是否相等
|
|
||||||
SaFoxUtil.getMarking28(); // 以当前时间戳和随机int数字拼接一个随机字符串
|
SaFoxUtil.getMarking28(); // 以当前时间戳和随机int数字拼接一个随机字符串
|
||||||
SaFoxUtil.formatDate(date); // 将日期格式化为yyyy-MM-dd HH:mm:ss字符串
|
SaFoxUtil.formatDate(date); // 将日期格式化为yyyy-MM-dd HH:mm:ss字符串
|
||||||
SaFoxUtil.searchList(dataList, prefix, keyword, start, size, sortType); // 从集合里查询数据
|
SaFoxUtil.searchList(dataList, prefix, keyword, start, size, sortType); // 从集合里查询数据
|
||||||
|
@ -27,6 +27,8 @@ implementation 'cn.dev33:sa-token-jwt:${sa.top.version}'
|
|||||||
|
|
||||||
> 注意: sa-token-jwt 显式依赖 hutool-jwt 5.7.14 版本,意味着:你的项目中要么不引入 Hutool,要么引入版本 >= 5.7.14 的 Hutool 版本
|
> 注意: sa-token-jwt 显式依赖 hutool-jwt 5.7.14 版本,意味着:你的项目中要么不引入 Hutool,要么引入版本 >= 5.7.14 的 Hutool 版本
|
||||||
|
|
||||||
|
> hutool 5.8.13 和 5.8.14 禁止使用, [关联issue](https://gitee.com/dromara/sa-token/issues/I6L429)
|
||||||
|
|
||||||
### 2、配置秘钥
|
### 2、配置秘钥
|
||||||
在 `application.yml` 配置文件中配置 jwt 生成秘钥:
|
在 `application.yml` 配置文件中配置 jwt 生成秘钥:
|
||||||
|
|
||||||
@ -139,8 +141,8 @@ eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbklkIjoiMTAwMDEiLCJybiI6IjZYYzgySzB
|
|||||||
| 功能点 | Simple 简单模式 | Mixin 混入模式 | Stateless 无状态模式 |
|
| 功能点 | Simple 简单模式 | Mixin 混入模式 | Stateless 无状态模式 |
|
||||||
| :-------- | :-------- | :-------- | :-------- |
|
| :-------- | :-------- | :-------- | :-------- |
|
||||||
| Token风格 | jwt风格 | jwt风格 | jwt风格 |
|
| Token风格 | jwt风格 | jwt风格 | jwt风格 |
|
||||||
| 登录数据存储 | Redis中 | Token中 | Token中 |
|
| 登录数据存储 | Redis中存储 | Token中存储 | Token中存储 |
|
||||||
| Session存储 | Redis中 | Redis中 | 无Session |
|
| Session存储 | Redis中存储 | Redis中存储 | 无Session |
|
||||||
| 注销下线 | 前后端双清数据 | 前后端双清数据 | 前端清除数据 |
|
| 注销下线 | 前后端双清数据 | 前后端双清数据 | 前端清除数据 |
|
||||||
| 踢人下线API | 支持 | 不支持 | 不支持 |
|
| 踢人下线API | 支持 | 不支持 | 不支持 |
|
||||||
| 顶人下线API | 支持 | 不支持 | 不支持 |
|
| 顶人下线API | 支持 | 不支持 | 不支持 |
|
||||||
|
@ -48,7 +48,13 @@ Sa-Token-Quick-Login的定位是这样的场景:你的项目需要一个登录
|
|||||||
<!---------------------------- tabs:start ------------------------------>
|
<!---------------------------- tabs:start ------------------------------>
|
||||||
<!-------- tab:Maven 方式 -------->
|
<!-------- tab:Maven 方式 -------->
|
||||||
``` xml
|
``` xml
|
||||||
<!-- Sa-Token-Quick-Login 插件 -->
|
<!-- Sa-Token 启动依赖 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.dev33</groupId>
|
||||||
|
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||||
|
<version>${sa.top.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- Sa-Token-Quick-Login 插件依赖 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.dev33</groupId>
|
<groupId>cn.dev33</groupId>
|
||||||
<artifactId>sa-token-quick-login</artifactId>
|
<artifactId>sa-token-quick-login</artifactId>
|
||||||
@ -57,6 +63,8 @@ Sa-Token-Quick-Login的定位是这样的场景:你的项目需要一个登录
|
|||||||
```
|
```
|
||||||
<!-------- tab:Gradle 方式 -------->
|
<!-------- tab:Gradle 方式 -------->
|
||||||
``` gradle
|
``` gradle
|
||||||
|
// Sa-Token 启动依赖
|
||||||
|
implementation 'cn.dev33:sa-token-spring-boot-starter:${sa.top.version}'
|
||||||
// Sa-Token-Quick-Login 插件
|
// Sa-Token-Quick-Login 插件
|
||||||
implementation 'cn.dev33:sa-token-quick-login:${sa.top.version}'
|
implementation 'cn.dev33:sa-token-quick-login:${sa.top.version}'
|
||||||
```
|
```
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
### 2、添加依赖
|
### 2、添加依赖
|
||||||
在项目中添加依赖:
|
在项目中添加依赖:
|
||||||
|
|
||||||
|
> 注:如果你使用的 `SpringBoot 3.x`,只需要将 `sa-token-spring-boot-starter` 修改为 `sa-token-spring-boot3-starter` 即可。
|
||||||
|
|
||||||
<!---------------------------- tabs:start ---------------------------->
|
<!---------------------------- tabs:start ---------------------------->
|
||||||
<!-------- tab:Maven 方式 -------->
|
<!-------- tab:Maven 方式 -------->
|
||||||
``` xml
|
``` xml
|
||||||
@ -30,7 +32,6 @@ implementation 'cn.dev33:sa-token-spring-boot-starter:${sa.top.version}'
|
|||||||
```
|
```
|
||||||
<!---------------------------- tabs:end ---------------------------->
|
<!---------------------------- tabs:end ---------------------------->
|
||||||
|
|
||||||
注:如果你使用的 `SpringBoot 3.x`,只需要将 `sa-token-spring-boot-starter` 修改为 `sa-token-spring-boot3-starter` 即可。
|
|
||||||
|
|
||||||
Maven依赖一直无法加载成功?[参考解决方案](https://sa-token.cc/doc.html#/start/maven-pull)
|
Maven依赖一直无法加载成功?[参考解决方案](https://sa-token.cc/doc.html#/start/maven-pull)
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package cn.dev33.satoken.dao;
|
package cn.dev33.satoken.dao;
|
||||||
|
|
||||||
import org.noear.redisx.RedisClient;
|
import org.noear.redisx.RedisClient;
|
||||||
import org.noear.solon.annotation.Note;
|
|
||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
@ -11,7 +10,6 @@ import java.util.Properties;
|
|||||||
* @author noear
|
* @author noear
|
||||||
* @since 1.6
|
* @since 1.6
|
||||||
*/
|
*/
|
||||||
@Note("更名为:SaTokenDaoOfRedisBase64")
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public class SaTokenDaoOfRedis extends SaTokenDaoOfRedisBase64 {
|
public class SaTokenDaoOfRedis extends SaTokenDaoOfRedisBase64 {
|
||||||
|
|
||||||
|
@ -41,5 +41,17 @@
|
|||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.noear</groupId>
|
||||||
|
<artifactId>snack3</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.noear</groupId>
|
||||||
|
<artifactId>redisx</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
@ -3,7 +3,6 @@ package cn.dev33.satoken.solon;
|
|||||||
import cn.dev33.satoken.solon.oauth2.SaOAuth2AutoConfigure;
|
import cn.dev33.satoken.solon.oauth2.SaOAuth2AutoConfigure;
|
||||||
import cn.dev33.satoken.solon.sso.SaSsoAutoConfigure;
|
import cn.dev33.satoken.solon.sso.SaSsoAutoConfigure;
|
||||||
import org.noear.solon.Solon;
|
import org.noear.solon.Solon;
|
||||||
import org.noear.solon.Utils;
|
|
||||||
import org.noear.solon.core.AopContext;
|
import org.noear.solon.core.AopContext;
|
||||||
import org.noear.solon.core.Plugin;
|
import org.noear.solon.core.Plugin;
|
||||||
|
|
||||||
@ -40,23 +39,11 @@ public class XPluginImp implements Plugin {
|
|||||||
|
|
||||||
|
|
||||||
//注入其它 Bean
|
//注入其它 Bean
|
||||||
context.beanOnloaded(c -> {
|
context.lifecycle(-99, () -> {
|
||||||
beanInitDo(c);
|
beanInitDo(context);
|
||||||
ssoBeanInitDo(c);
|
|
||||||
oauth2BeanInitDo(c);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ssoBeanInitDo(AopContext context){
|
|
||||||
if (Utils.loadClass("cn.dev33.satoken.sso.SaSsoManager") != null) {
|
|
||||||
context.beanMake(SaSsoAutoConfigure.class);
|
context.beanMake(SaSsoAutoConfigure.class);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void oauth2BeanInitDo(AopContext context){
|
|
||||||
if(Utils.loadClass("cn.dev33.satoken.oauth2.SaOAuth2Manager") != null){
|
|
||||||
context.beanMake(SaOAuth2AutoConfigure.class);
|
context.beanMake(SaOAuth2AutoConfigure.class);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void beanInitDo(AopContext context) {
|
private void beanInitDo(AopContext context) {
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
package cn.dev33.satoken.solon.dao;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.session.SaSession;
|
||||||
|
import cn.dev33.satoken.util.SaFoxUtil;
|
||||||
|
import org.noear.snack.ONode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Snack3 定制版 SaSession,重写类型转换API
|
||||||
|
*
|
||||||
|
* @author noear
|
||||||
|
* @since 1.12
|
||||||
|
*/
|
||||||
|
public class SaSessionForJson extends SaSession {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -7600983549653130681L;
|
||||||
|
|
||||||
|
public SaSessionForJson() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建一个 SaSession 对象
|
||||||
|
* @param id Session 的 id
|
||||||
|
*/
|
||||||
|
public SaSessionForJson(String id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取值 (指定转换类型)
|
||||||
|
* @param <T> 泛型
|
||||||
|
* @param key key
|
||||||
|
* @param cs 指定转换类型
|
||||||
|
* @return 值
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> T getModel(String key, Class<T> cs) {
|
||||||
|
if(SaFoxUtil.isBasicType(cs)) {
|
||||||
|
return SaFoxUtil.getValueByType(get(key), cs);
|
||||||
|
}
|
||||||
|
return ONode.deserialize(getString(key), cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取值 (指定转换类型, 并指定值为Null时返回的默认值)
|
||||||
|
* @param <T> 泛型
|
||||||
|
* @param key key
|
||||||
|
* @param cs 指定转换类型
|
||||||
|
* @param defaultValue 值为Null时返回的默认值
|
||||||
|
* @return 值
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T getModel(String key, Class<T> cs, Object defaultValue) {
|
||||||
|
Object value = get(key);
|
||||||
|
if(valueIsNull(value)) {
|
||||||
|
return (T)defaultValue;
|
||||||
|
}
|
||||||
|
if(SaFoxUtil.isBasicType(cs)) {
|
||||||
|
return SaFoxUtil.getValueByType(get(key), cs);
|
||||||
|
}
|
||||||
|
return ONode.deserialize(getString(key), cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 忽略 timeout 字段的序列化
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public long getTimeout() {
|
||||||
|
return super.getTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package cn.dev33.satoken.solon.dao;
|
||||||
|
|
||||||
|
import org.noear.redisx.RedisClient;
|
||||||
|
import org.noear.solon.annotation.Note;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SaTokenDao 的 redis 适配
|
||||||
|
*
|
||||||
|
* @author noear
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
public class SaTokenDaoOfRedis extends SaTokenDaoOfRedisBase64 {
|
||||||
|
|
||||||
|
public SaTokenDaoOfRedis(Properties props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SaTokenDaoOfRedis(RedisClient redisClient) {
|
||||||
|
super(redisClient);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,186 @@
|
|||||||
|
package cn.dev33.satoken.solon.dao;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.dao.SaTokenDao;
|
||||||
|
import cn.dev33.satoken.util.SaFoxUtil;
|
||||||
|
import org.noear.redisx.RedisClient;
|
||||||
|
import org.noear.redisx.plus.RedisBucket;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SaTokenDao 的 redis 适配(可以完全精准还原所有序列化类型)
|
||||||
|
*
|
||||||
|
* @author noear
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
public class SaTokenDaoOfRedisBase64 implements SaTokenDao {
|
||||||
|
private final RedisBucket redisBucket;
|
||||||
|
|
||||||
|
public SaTokenDaoOfRedisBase64(Properties props) {
|
||||||
|
this(new RedisClient(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
public SaTokenDaoOfRedisBase64(RedisClient redisClient) {
|
||||||
|
redisBucket = redisClient.getBucket();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Value,如无返空
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String get(String key) {
|
||||||
|
return redisBucket.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入Value,并设定存活时间 (单位: 秒)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void set(String key, String value, long timeout) {
|
||||||
|
if (timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 判断是否为永不过期
|
||||||
|
if (timeout == SaTokenDao.NEVER_EXPIRE) {
|
||||||
|
redisBucket.store(key, value, (int) SaTokenDao.NEVER_EXPIRE);
|
||||||
|
} else {
|
||||||
|
redisBucket.store(key, value, (int) timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改指定key-value键值对 (过期时间不变)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void update(String key, String value) {
|
||||||
|
long expire = getTimeout(key);
|
||||||
|
// -2 = 无此键
|
||||||
|
if (expire == SaTokenDao.NOT_VALUE_EXPIRE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.set(key, value, expire);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除Value
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void delete(String key) {
|
||||||
|
redisBucket.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Value的剩余存活时间 (单位: 秒)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public long getTimeout(String key) {
|
||||||
|
return redisBucket.ttl(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改Value的剩余存活时间 (单位: 秒)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updateTimeout(String key, long timeout) {
|
||||||
|
// 判断是否想要设置为永久
|
||||||
|
if (timeout == SaTokenDao.NEVER_EXPIRE) {
|
||||||
|
long expire = getTimeout(key);
|
||||||
|
if (expire == SaTokenDao.NEVER_EXPIRE) {
|
||||||
|
// 如果其已经被设置为永久,则不作任何处理
|
||||||
|
} else {
|
||||||
|
// 如果尚未被设置为永久,那么再次set一次
|
||||||
|
this.set(key, this.get(key), timeout);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
redisBucket.delay(key, (int) timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Object,如无返空
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object getObject(String key) {
|
||||||
|
return redisBucket.getAndDeserialize(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入Object,并设定存活时间 (单位: 秒)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setObject(String key, Object object, long timeout) {
|
||||||
|
if (timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 判断是否为永不过期
|
||||||
|
if (timeout == SaTokenDao.NEVER_EXPIRE) {
|
||||||
|
redisBucket.storeAndSerialize(key, object);
|
||||||
|
} else {
|
||||||
|
redisBucket.storeAndSerialize(key, object, (int) timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新Object (过期时间不变)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updateObject(String key, Object object) {
|
||||||
|
long expire = getObjectTimeout(key);
|
||||||
|
// -2 = 无此键
|
||||||
|
if (expire == SaTokenDao.NOT_VALUE_EXPIRE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setObject(key, object, expire);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除Object
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void deleteObject(String key) {
|
||||||
|
redisBucket.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Object的剩余存活时间 (单位: 秒)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public long getObjectTimeout(String key) {
|
||||||
|
return redisBucket.ttl(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改Object的剩余存活时间 (单位: 秒)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updateObjectTimeout(String key, long timeout) {
|
||||||
|
// 判断是否想要设置为永久
|
||||||
|
if (timeout == SaTokenDao.NEVER_EXPIRE) {
|
||||||
|
long expire = getObjectTimeout(key);
|
||||||
|
if (expire == SaTokenDao.NEVER_EXPIRE) {
|
||||||
|
// 如果其已经被设置为永久,则不作任何处理
|
||||||
|
} else {
|
||||||
|
// 如果尚未被设置为永久,那么再次set一次
|
||||||
|
this.setObject(key, this.getObject(key), timeout);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
redisBucket.delay(key, (int) timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索数据
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
|
||||||
|
Set<String> keys = redisBucket.keys(prefix + "*" + keyword + "*");
|
||||||
|
List<String> list = new ArrayList<String>(keys);
|
||||||
|
return SaFoxUtil.searchList(list, start, size, sortType);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,199 @@
|
|||||||
|
package cn.dev33.satoken.solon.dao;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.dao.SaTokenDao;
|
||||||
|
import cn.dev33.satoken.session.SaSession;
|
||||||
|
import cn.dev33.satoken.strategy.SaStrategy;
|
||||||
|
import cn.dev33.satoken.util.SaFoxUtil;
|
||||||
|
import org.noear.redisx.RedisClient;
|
||||||
|
import org.noear.redisx.plus.RedisBucket;
|
||||||
|
import org.noear.snack.ONode;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SaTokenDao 的 redis 适配(基于json序列化,不能完全精准还原所有类型)
|
||||||
|
*
|
||||||
|
* @author noear
|
||||||
|
* @since 1.6
|
||||||
|
*/
|
||||||
|
public class SaTokenDaoOfRedisJson implements SaTokenDao {
|
||||||
|
private final RedisBucket redisBucket;
|
||||||
|
|
||||||
|
public SaTokenDaoOfRedisJson(Properties props) {
|
||||||
|
this(new RedisClient(props));
|
||||||
|
}
|
||||||
|
|
||||||
|
public SaTokenDaoOfRedisJson(RedisClient redisClient) {
|
||||||
|
redisBucket = redisClient.getBucket();
|
||||||
|
|
||||||
|
// 重写 SaSession 生成策略
|
||||||
|
SaStrategy.me.createSession = (sessionId) -> new SaSessionForJson(sessionId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SaSession getSession(String sessionId) {
|
||||||
|
Object obj = getObject(sessionId);
|
||||||
|
if (obj == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return ONode.deserialize(obj.toString(), SaSessionForJson.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Value,如无返空
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String get(String key) {
|
||||||
|
return redisBucket.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入Value,并设定存活时间 (单位: 秒)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void set(String key, String value, long timeout) {
|
||||||
|
if (timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 判断是否为永不过期
|
||||||
|
if (timeout == SaTokenDao.NEVER_EXPIRE) {
|
||||||
|
redisBucket.store(key, value, (int) SaTokenDao.NEVER_EXPIRE);
|
||||||
|
} else {
|
||||||
|
redisBucket.store(key, value, (int) timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改指定key-value键值对 (过期时间不变)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void update(String key, String value) {
|
||||||
|
long expire = getTimeout(key);
|
||||||
|
// -2 = 无此键
|
||||||
|
if (expire == SaTokenDao.NOT_VALUE_EXPIRE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.set(key, value, expire);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除Value
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void delete(String key) {
|
||||||
|
redisBucket.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Value的剩余存活时间 (单位: 秒)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public long getTimeout(String key) {
|
||||||
|
return redisBucket.ttl(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改Value的剩余存活时间 (单位: 秒)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updateTimeout(String key, long timeout) {
|
||||||
|
// 判断是否想要设置为永久
|
||||||
|
if (timeout == SaTokenDao.NEVER_EXPIRE) {
|
||||||
|
long expire = getTimeout(key);
|
||||||
|
if (expire == SaTokenDao.NEVER_EXPIRE) {
|
||||||
|
// 如果其已经被设置为永久,则不作任何处理
|
||||||
|
} else {
|
||||||
|
// 如果尚未被设置为永久,那么再次set一次
|
||||||
|
this.set(key, this.get(key), timeout);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
redisBucket.delay(key, (int) timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Object,如无返空
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object getObject(String key) {
|
||||||
|
return get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入Object,并设定存活时间 (单位: 秒)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setObject(String key, Object object, long timeout) {
|
||||||
|
if (timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String value = ONode.serialize(object);
|
||||||
|
set(key, value, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新Object (过期时间不变)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updateObject(String key, Object object) {
|
||||||
|
long expire = getObjectTimeout(key);
|
||||||
|
// -2 = 无此键
|
||||||
|
if (expire == SaTokenDao.NOT_VALUE_EXPIRE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setObject(key, object, expire);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除Object
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void deleteObject(String key) {
|
||||||
|
redisBucket.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Object的剩余存活时间 (单位: 秒)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public long getObjectTimeout(String key) {
|
||||||
|
return redisBucket.ttl(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改Object的剩余存活时间 (单位: 秒)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updateObjectTimeout(String key, long timeout) {
|
||||||
|
// 判断是否想要设置为永久
|
||||||
|
if (timeout == SaTokenDao.NEVER_EXPIRE) {
|
||||||
|
long expire = getObjectTimeout(key);
|
||||||
|
if (expire == SaTokenDao.NEVER_EXPIRE) {
|
||||||
|
// 如果其已经被设置为永久,则不作任何处理
|
||||||
|
} else {
|
||||||
|
// 如果尚未被设置为永久,那么再次set一次
|
||||||
|
this.setObject(key, this.getObject(key), timeout);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
redisBucket.delay(key, (int) timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索数据
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
|
||||||
|
Set<String> keys = redisBucket.keys(prefix + "*" + keyword + "*");
|
||||||
|
List<String> list = new ArrayList<String>(keys);
|
||||||
|
return SaFoxUtil.searchList(list, start, size, sortType);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package cn.dev33.satoken.solon.json;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.json.SaJsonTemplate;
|
||||||
|
import org.noear.snack.ONode;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author noear
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
public class SaJsonTemplateForSnack3 implements SaJsonTemplate {
|
||||||
|
@Override
|
||||||
|
public String toJsonString(Object o) {
|
||||||
|
return ONode.stringify(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> parseJsonToMap(String s) {
|
||||||
|
return ONode.deserialize(s, Map.class);
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
|
|||||||
import cn.dev33.satoken.oauth2.logic.SaOAuth2Template;
|
import cn.dev33.satoken.oauth2.logic.SaOAuth2Template;
|
||||||
import cn.dev33.satoken.oauth2.logic.SaOAuth2Util;
|
import cn.dev33.satoken.oauth2.logic.SaOAuth2Util;
|
||||||
import org.noear.solon.annotation.Bean;
|
import org.noear.solon.annotation.Bean;
|
||||||
|
import org.noear.solon.annotation.Condition;
|
||||||
import org.noear.solon.annotation.Configuration;
|
import org.noear.solon.annotation.Configuration;
|
||||||
import org.noear.solon.annotation.Inject;
|
import org.noear.solon.annotation.Inject;
|
||||||
|
|
||||||
@ -12,13 +13,14 @@ import org.noear.solon.annotation.Inject;
|
|||||||
* @author noear
|
* @author noear
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
|
@Condition(onClass = SaOAuth2Manager.class)
|
||||||
@Configuration
|
@Configuration
|
||||||
public class SaOAuth2AutoConfigure {
|
public class SaOAuth2AutoConfigure {
|
||||||
/**
|
/**
|
||||||
* 获取 OAuth2配置Bean
|
* 获取 OAuth2配置Bean
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public SaOAuth2Config getConfig(@Inject(value = "${sa-token.oauth2}",required = false) SaOAuth2Config oAuth2Config) {
|
public SaOAuth2Config getConfig(@Inject(value = "${sa-token.oauth2}", required = false) SaOAuth2Config oAuth2Config) {
|
||||||
return oAuth2Config;
|
return oAuth2Config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,15 +6,15 @@ import cn.dev33.satoken.sso.SaSsoProcessor;
|
|||||||
import cn.dev33.satoken.sso.SaSsoTemplate;
|
import cn.dev33.satoken.sso.SaSsoTemplate;
|
||||||
import cn.dev33.satoken.sso.SaSsoUtil;
|
import cn.dev33.satoken.sso.SaSsoUtil;
|
||||||
import org.noear.solon.annotation.Bean;
|
import org.noear.solon.annotation.Bean;
|
||||||
|
import org.noear.solon.annotation.Condition;
|
||||||
import org.noear.solon.annotation.Configuration;
|
import org.noear.solon.annotation.Configuration;
|
||||||
import org.noear.solon.annotation.Init;
|
|
||||||
import org.noear.solon.annotation.Inject;
|
import org.noear.solon.annotation.Inject;
|
||||||
import org.noear.solon.core.AopContext;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author noear
|
* @author noear
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
|
@Condition(onClass = SaSsoManager.class)
|
||||||
@Configuration
|
@Configuration
|
||||||
public class SaSsoAutoConfigure {
|
public class SaSsoAutoConfigure {
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user