mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-04-05 17:37:53 +08:00
第一版
This commit is contained in:
parent
9a372b742d
commit
3329910bdd
@ -1,2 +1,4 @@
|
||||
# sa-token
|
||||
一个好用的JavaWeb权限认证框架
|
||||
|
||||
在线文档:[http://sa-token.dev33.cn/](http://sa-token.dev33.cn/)
|
32
sa-token-demo-springboot/.classpath
Normal file
32
sa-token-demo-springboot/.classpath
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
6
sa-token-demo-springboot/.gitignore
vendored
Normal file
6
sa-token-demo-springboot/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
target/
|
||||
|
||||
node_modules/
|
||||
bin/
|
||||
.settings/
|
||||
unpackage/
|
23
sa-token-demo-springboot/.project
Normal file
23
sa-token-demo-springboot/.project
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>sa-token-demo-springboot</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
BIN
sa-token-demo-springboot/lib/sa-token-spring-1.0.0.jar
Normal file
BIN
sa-token-demo-springboot/lib/sa-token-spring-1.0.0.jar
Normal file
Binary file not shown.
90
sa-token-demo-springboot/pom.xml
Normal file
90
sa-token-demo-springboot/pom.xml
Normal file
@ -0,0 +1,90 @@
|
||||
<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>sa-token-demo-springboot</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
||||
<!-- SpringBoot -->
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.0.0.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- springboot依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- sa-token 安全认证 -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33.sa-token</groupId>
|
||||
<artifactId>sa-token-spring</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/lib/sa-token-spring-1.0.0.jar</systemPath>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot整合redis -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-redis</artifactId>
|
||||
<version>RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<!-- 配置打包 -->
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- 打包jar文件时,配置manifest文件,加入lib包的jar依赖 -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addClasspath>true</addClasspath>
|
||||
<classpathPrefix>lib/</classpathPrefix>
|
||||
<mainClass>com.pj.SaTokenDemoApplication</mainClass>
|
||||
</manifest>
|
||||
<!-- jar清单添加此字符串 -->
|
||||
<manifestEntries>
|
||||
<Class-Path>lib/sa-token-spring-1.0.0.jar</Class-Path>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- 拷贝依赖的jar包到lib目录 -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>
|
||||
${project.build.directory}/lib
|
||||
</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
@ -0,0 +1,18 @@
|
||||
package com.pj;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
|
||||
import cn.dev33.satoken.spring.SaTokenSetup;
|
||||
|
||||
@SaTokenSetup // 标注启动 sa-token
|
||||
@SpringBootApplication
|
||||
public class SaTokenDemoApplication {
|
||||
|
||||
public static void main(String[] args) throws JsonProcessingException {
|
||||
SpringApplication.run(SaTokenDemoApplication.class, args); // run-->
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package com.pj.satoken;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
// import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
|
||||
/**
|
||||
* sa-token持久层的实现类 , 基于redis
|
||||
*/
|
||||
// @Component // 打开此注解,保证此类被springboot扫描,即可完成sa-token与redis的集成
|
||||
public class SaTokenDaoRedis implements SaTokenDao {
|
||||
|
||||
|
||||
// string专用
|
||||
@Autowired
|
||||
StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
// SaSession专用
|
||||
RedisTemplate<String, SaSession> redisTemplate;
|
||||
@Autowired
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void setRedisTemplate(RedisTemplate redisTemplate) {
|
||||
RedisSerializer stringSerializer = new StringRedisSerializer();
|
||||
redisTemplate.setKeySerializer(stringSerializer);
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
|
||||
// 根据key获取value ,如果没有,则返回空
|
||||
@Override
|
||||
public String getValue(String key) {
|
||||
return stringRedisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
// 写入指定key-value键值对,并设定过期时间(单位:秒)
|
||||
@Override
|
||||
public void setValue(String key, String value, long timeout) {
|
||||
stringRedisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
// 删除一个指定的key
|
||||
@Override
|
||||
public void delKey(String key) {
|
||||
stringRedisTemplate.delete(key);
|
||||
}
|
||||
|
||||
|
||||
// 根据指定key的session,如果没有,则返回空
|
||||
@Override
|
||||
public SaSession getSaSession(String sessionId) {
|
||||
return redisTemplate.opsForValue().get(sessionId);
|
||||
}
|
||||
|
||||
// 将指定session持久化
|
||||
@Override
|
||||
public void saveSaSession(SaSession session, long timeout) {
|
||||
redisTemplate.opsForValue().set(session.getId(), session, timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
// 更新指定session
|
||||
@Override
|
||||
public void updateSaSession(SaSession session) {
|
||||
long expire = redisTemplate.getExpire(session.getId());
|
||||
if(expire == -2) { // -2 = 无此键
|
||||
return;
|
||||
}
|
||||
redisTemplate.opsForValue().set(session.getId(), session, expire, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
// 删除一个指定的session
|
||||
@Override
|
||||
public void delSaSession(String sessionId) {
|
||||
redisTemplate.delete(sessionId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.pj.satoken;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
|
||||
/**
|
||||
* 自定义权限验证接口扩展
|
||||
*/
|
||||
@Component // 打开此注解,保证此类被springboot扫描,即可完成sa-token的自定义权限验证扩展
|
||||
public class StpCustom implements StpInterface {
|
||||
|
||||
@Override
|
||||
public List<Object> getPermissionCodeList(Object login_id, String login_key) {
|
||||
List<Object> list = new ArrayList<Object>();
|
||||
list.add("101");
|
||||
list.add("user-add");
|
||||
list.add("user-delete");
|
||||
list.add("user-update");
|
||||
list.add("user-get");
|
||||
list.add("article-get");
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
163
sa-token-demo-springboot/src/main/java/com/pj/test/AjaxJson.java
Normal file
163
sa-token-demo-springboot/src/main/java/com/pj/test/AjaxJson.java
Normal file
@ -0,0 +1,163 @@
|
||||
package com.pj.test;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* ajax返回Json的封装
|
||||
* 【此类封装了Meta和Body的功能,写法不同,但是返回数据格式相同】
|
||||
*/
|
||||
public class AjaxJson implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = 1L; // 序列化版本号
|
||||
|
||||
public static final int CODE_SUCCESS = 200; // 成功状态码
|
||||
public static final int CODE_ERROR = 500; // 错误状态码
|
||||
public static final int CODE_WARNING = 501; // 警告状态码
|
||||
public static final int CODE_NOT_JUR = 403; // 无权限状态码
|
||||
public static final int CODE_NOT_LOGIN = 401; // 未登录状态码
|
||||
public static final int CODE_INVALID_REQUEST = 400; // 无效请求状态码
|
||||
|
||||
public int code; // 状态码
|
||||
public String msg; // 描述信息
|
||||
public Object data; // 携带对象
|
||||
public Long dataCount; // 数据总数
|
||||
|
||||
/**
|
||||
* 返回code
|
||||
* @return
|
||||
*/
|
||||
public int getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 给msg赋值,连缀风格
|
||||
*/
|
||||
public AjaxJson setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
return this;
|
||||
}
|
||||
public String getMsg() {
|
||||
return this.msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 给data赋值,连缀风格
|
||||
*/
|
||||
public AjaxJson setData(Object data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将data还原为指定类型并返回
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getData(Class<T> cs) {
|
||||
return (T) data;
|
||||
}
|
||||
|
||||
// ============================ 构建 ==================================
|
||||
|
||||
public AjaxJson(int code, String msg, Object data, Long dataCount) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
this.data = data;
|
||||
this.dataCount = dataCount;
|
||||
}
|
||||
|
||||
// 返回成功
|
||||
public static AjaxJson getSuccess() {
|
||||
return new AjaxJson(CODE_SUCCESS, "ok", null, null);
|
||||
}
|
||||
public static AjaxJson getSuccess(String msg) {
|
||||
return new AjaxJson(CODE_SUCCESS, msg, null, null);
|
||||
}
|
||||
public static AjaxJson getSuccess(String msg, Object data) {
|
||||
return new AjaxJson(CODE_SUCCESS, msg, data, null);
|
||||
}
|
||||
public static AjaxJson getSuccessData(Object data) {
|
||||
return new AjaxJson(CODE_SUCCESS, "ok", data, null);
|
||||
}
|
||||
public static AjaxJson getSuccessArray(Object... data) {
|
||||
return new AjaxJson(CODE_SUCCESS, "ok", data, null);
|
||||
}
|
||||
|
||||
// 返回失败
|
||||
public static AjaxJson getError() {
|
||||
return new AjaxJson(CODE_ERROR, "error", null, null);
|
||||
}
|
||||
public static AjaxJson getError(String msg) {
|
||||
return new AjaxJson(CODE_ERROR, msg, null, null);
|
||||
}
|
||||
|
||||
// 返回警告
|
||||
public static AjaxJson getWarning() {
|
||||
return new AjaxJson(CODE_ERROR, "warning", null, null);
|
||||
}
|
||||
public static AjaxJson getWarning(String msg) {
|
||||
return new AjaxJson(CODE_WARNING, msg, null, null);
|
||||
}
|
||||
|
||||
// 返回未登录
|
||||
public static AjaxJson getNotLogin() {
|
||||
return new AjaxJson(CODE_NOT_LOGIN, "未登录,请登录后再次访问", null, null);
|
||||
}
|
||||
|
||||
// 返回没有权限的
|
||||
public static AjaxJson getNotJur(String msg) {
|
||||
return new AjaxJson(CODE_NOT_JUR, msg, null, null);
|
||||
}
|
||||
|
||||
// 返回一个自定义状态码的
|
||||
public static AjaxJson get(int code, String msg){
|
||||
return new AjaxJson(code, msg, null, null);
|
||||
}
|
||||
|
||||
// 返回分页和数据的
|
||||
public static AjaxJson getPageData(Long dataCount, Object data){
|
||||
return new AjaxJson(CODE_SUCCESS, "ok", data, dataCount);
|
||||
}
|
||||
|
||||
// 返回,根据受影响行数的(大于0=ok,小于0=error)
|
||||
public static AjaxJson getByLine(int line){
|
||||
if(line > 0){
|
||||
return getSuccess("ok", line);
|
||||
}
|
||||
return getError("error").setData(line);
|
||||
}
|
||||
|
||||
// 返回,根据布尔值来确定最终结果的 (true=ok,false=error)
|
||||
public static AjaxJson getByBoolean(boolean b){
|
||||
return b ? getSuccess("ok") : getError("error");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public String toString() {
|
||||
String data_string = null;
|
||||
if(data == null){
|
||||
|
||||
} else if(data instanceof List){
|
||||
data_string = "List(length=" + ((List)data).size() + ")";
|
||||
} else {
|
||||
data_string = data.toString();
|
||||
}
|
||||
return "{"
|
||||
+ "\"code\": " + this.getCode()
|
||||
+ ", \"msg\": \"" + this.getMsg() + "\""
|
||||
+ ", \"data\": " + data_string
|
||||
+ ", \"dataCount\": " + dataCount
|
||||
+ "}";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package com.pj.test;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import cn.dev33.satoken.session.SaSessionUtil;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/test/")
|
||||
public class TestController {
|
||||
|
||||
// 测试登录接口, 浏览器访问: http://localhost:8081/test/login
|
||||
@RequestMapping("login")
|
||||
public AjaxJson login(@RequestParam(defaultValue="10001") String id) {
|
||||
System.out.println("======================= 进入方法,测试登录接口 ========================= ");
|
||||
System.out.println("当前会话的token:" + StpUtil.getTokenValue());
|
||||
System.out.println("当前是否登录:" + StpUtil.isLogin());
|
||||
System.out.println("当前登录账号:" + StpUtil.getLoginId_defaultNull());
|
||||
StpUtil.setLoginId(id); // 在当前会话登录此账号
|
||||
System.out.println("登录成功");
|
||||
System.out.println("当前是否登录:" + StpUtil.isLogin());
|
||||
System.out.println("当前登录账号:" + StpUtil.getLoginId());
|
||||
System.out.println("当前登录账号:" + StpUtil.getLoginId_asInt()); // 获取登录id并转为int
|
||||
|
||||
System.out.println("当前token信息:" + StpUtil.getTokenInfo()); // 获取登录id并转为int
|
||||
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
// 测试权限接口, 浏览器访问: http://localhost:8081/test/jur
|
||||
@RequestMapping("jur")
|
||||
public AjaxJson jur() {
|
||||
System.out.println("======================= 进入方法,测试权限接口 ========================= ");
|
||||
|
||||
System.out.println("是否具有权限101" + StpUtil.hasPermission(101));
|
||||
System.out.println("是否具有权限user-add" + StpUtil.hasPermission("user-add"));
|
||||
System.out.println("是否具有权限article-get" + StpUtil.hasPermission("article-get"));
|
||||
|
||||
System.out.println("没有user-add权限就抛出异常");
|
||||
StpUtil.checkPermission("user-add");
|
||||
|
||||
System.out.println("在【101、102】中只要拥有一个就不会抛出异常");
|
||||
StpUtil.checkPermissionOr("101", "102");
|
||||
|
||||
System.out.println("在【101、102】中必须全部拥有才不会抛出异常");
|
||||
StpUtil.checkPermissionAnd("101", "102");
|
||||
|
||||
System.out.println("权限测试通过");
|
||||
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
// 测试会话session接口, 浏览器访问: http://localhost:8081/test/session
|
||||
@RequestMapping("session")
|
||||
public AjaxJson session() {
|
||||
System.out.println("======================= 进入方法,测试会话session接口 ========================= ");
|
||||
System.out.println("当前是否登录:" + StpUtil.isLogin());
|
||||
System.out.println("当前登录账号session的id" + StpUtil.getSession().getId());
|
||||
System.out.println("当前登录账号session的id" + StpUtil.getSession().getId());
|
||||
System.out.println("测试取值name:" + StpUtil.getSession().getAttribute("name"));
|
||||
StpUtil.getSession().setAttribute("name", "张三"); // 写入一个值
|
||||
System.out.println("测试取值name:" + StpUtil.getSession().getAttribute("name"));
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
// 测试自定义session接口, 浏览器访问: http://localhost:8081/test/session2
|
||||
@RequestMapping("session2")
|
||||
public AjaxJson session2() {
|
||||
System.out.println("======================= 进入方法,测试自定义session接口 ========================= ");
|
||||
// 自定义session就是无需登录也可以使用 的session :比如拿用户的手机号当做 key, 来获取 session
|
||||
System.out.println("自定义 session的id为:" + SaSessionUtil.getSessionById("1895544896").getId());
|
||||
System.out.println("测试取值name:" + SaSessionUtil.getSessionById("1895544896").getAttribute("name"));
|
||||
SaSessionUtil.getSessionById("1895544896").setAttribute("name", "张三"); // 写入值
|
||||
System.out.println("测试取值name:" + SaSessionUtil.getSessionById("1895544896").getAttribute("name"));
|
||||
System.out.println("测试取值name:" + SaSessionUtil.getSessionById("1895544896").getAttribute("name"));
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.pj.test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.exception.NotPermissionException;
|
||||
|
||||
/**
|
||||
* 加强版控制器
|
||||
*/
|
||||
@ControllerAdvice // 可指定包前缀,比如:(basePackages = "com.zyd.blog.controller.admin")
|
||||
public class TopController {
|
||||
|
||||
// 在每个控制器之前触发的操作
|
||||
@ModelAttribute
|
||||
public void get(HttpServletRequest request) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
// 全局异常拦截(拦截项目中的所有异常)
|
||||
@ExceptionHandler
|
||||
public void handlerException(Exception e, HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception {
|
||||
|
||||
e.printStackTrace(); // 打印堆栈,以供调试
|
||||
|
||||
response.setContentType("application/json; charset=utf-8"); // http说明,我要返回JSON对象
|
||||
|
||||
// 如果是未登录异常
|
||||
if (e instanceof NotLoginException) {
|
||||
String jsonStr = new ObjectMapper().writeValueAsString(AjaxJson.getNotLogin());
|
||||
response.getWriter().print(jsonStr);
|
||||
return;
|
||||
}
|
||||
// 如果是权限异常
|
||||
if (e instanceof NotPermissionException) {
|
||||
NotPermissionException ee = (NotPermissionException) e;
|
||||
String jsonStr = new ObjectMapper().writeValueAsString(AjaxJson.getNotJur("无此权限:" + ee.getCode()));
|
||||
response.getWriter().print(jsonStr);
|
||||
return;
|
||||
}
|
||||
|
||||
// 普通异常输出:500 + 异常信息
|
||||
response.getWriter().print(new ObjectMapper().writeValueAsString(AjaxJson.getError(e.getMessage())));
|
||||
|
||||
}
|
||||
|
||||
}
|
44
sa-token-demo-springboot/src/main/resources/application.yml
Normal file
44
sa-token-demo-springboot/src/main/resources/application.yml
Normal file
@ -0,0 +1,44 @@
|
||||
# 端口
|
||||
server:
|
||||
port: 8081
|
||||
|
||||
spring:
|
||||
# sa-token配置
|
||||
sa-token:
|
||||
# token名称(同时也是cookie名称)
|
||||
token-name: satoken
|
||||
# token有效期,单位s 默认30天,-1为永不过期
|
||||
timeout: 2592000
|
||||
# 在多人登录同一账号时,是否共享会话(为true时共用一个,为false时新登录挤掉旧登录)
|
||||
is-share: true
|
||||
# 是否在cookie读取不到token时,继续从请求header里继续尝试读取
|
||||
is-read-head: true
|
||||
# 是否在header读取不到token时,继续从请求题参数里继续尝试读取
|
||||
is-read-body: true
|
||||
# 是否在初始化配置时打印版本字符画
|
||||
is-v: true
|
||||
|
||||
|
||||
# redis配置
|
||||
redis:
|
||||
# Redis数据库索引(默认为0)
|
||||
database: 1
|
||||
# Redis服务器地址
|
||||
host: 127.0.0.1
|
||||
# Redis服务器连接端口
|
||||
port: 6379
|
||||
# Redis服务器连接密码(默认为空)
|
||||
password:
|
||||
# 连接池最大连接数(使用负值表示没有限制)
|
||||
pool:
|
||||
maxActive: 20
|
||||
# 连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
maxWait: -1
|
||||
# 连接池中的最大空闲连接
|
||||
maxIdle: 8
|
||||
# 连接池中的最小空闲连接
|
||||
minIdle: 1
|
||||
# 连接超时时间(毫秒)
|
||||
timeout: 0
|
||||
|
||||
|
32
sa-token-dev/.classpath
Normal file
32
sa-token-dev/.classpath
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
6
sa-token-dev/.gitignore
vendored
Normal file
6
sa-token-dev/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
target/
|
||||
|
||||
node_modules/
|
||||
bin/
|
||||
.settings/
|
||||
unpackage/
|
23
sa-token-dev/.project
Normal file
23
sa-token-dev/.project
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>sa-token-dev</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
31
sa-token-dev/pom.xml
Normal file
31
sa-token-dev/pom.xml
Normal file
@ -0,0 +1,31 @@
|
||||
<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>sa-token-dev</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
||||
<!-- SpringBoot -->
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.0.0.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- springboot依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
@ -0,0 +1,78 @@
|
||||
package cn.dev33.satoken;
|
||||
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.config.SaTokenConfigFactory;
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.dao.SaTokenDaoDefault;
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
import cn.dev33.satoken.stp.StpInterfaceDefaultImpl;
|
||||
|
||||
/**
|
||||
* 管理sa-token所有对象
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenManager {
|
||||
|
||||
// 配置文件 Bean
|
||||
private static SaTokenConfig config;
|
||||
public static SaTokenConfig getConfig() {
|
||||
if (config == null) {
|
||||
initConfig();
|
||||
}
|
||||
return config;
|
||||
}
|
||||
public static void setConfig(SaTokenConfig config) {
|
||||
SaTokenManager.config = config;
|
||||
if(config.getIsV()) {
|
||||
SaTokenUtil.printSaToken();
|
||||
}
|
||||
}
|
||||
public synchronized static void initConfig() {
|
||||
if (config == null) {
|
||||
setConfig(SaTokenConfigFactory.createConfig());
|
||||
}
|
||||
}
|
||||
|
||||
// 持久化 Bean
|
||||
public static SaTokenDao dao;
|
||||
public static SaTokenDao getDao() {
|
||||
if (dao == null) {
|
||||
initDao();
|
||||
}
|
||||
return dao;
|
||||
}
|
||||
public static void setDao(SaTokenDao dao) {
|
||||
SaTokenManager.dao = dao;
|
||||
}
|
||||
public synchronized static void initDao() {
|
||||
if (dao == null) {
|
||||
setDao(new SaTokenDaoDefault());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 权限认证 Bean
|
||||
public static StpInterface stp;
|
||||
public static StpInterface getStp() {
|
||||
if (stp == null) {
|
||||
initStp();
|
||||
}
|
||||
return stp;
|
||||
}
|
||||
public static void setStp(StpInterface stp) {
|
||||
SaTokenManager.stp = stp;
|
||||
}
|
||||
public synchronized static void initStp() {
|
||||
if (stp == null) {
|
||||
setStp(new StpInterfaceDefaultImpl());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
30
sa-token-dev/src/main/java/cn/dev33/satoken/SaTokenUtil.java
Normal file
30
sa-token-dev/src/main/java/cn/dev33/satoken/SaTokenUtil.java
Normal file
@ -0,0 +1,30 @@
|
||||
package cn.dev33.satoken;
|
||||
|
||||
/**
|
||||
* sa-token 工具类
|
||||
*/
|
||||
public class SaTokenUtil {
|
||||
|
||||
|
||||
// sa-token 版本号
|
||||
public static final String version = "v1.0.0";
|
||||
|
||||
// sa-token 开源地址
|
||||
public static final String github_url = "https://github.com/click33/sa-token";
|
||||
|
||||
// 打印 sa-token
|
||||
public static void printSaToken() {
|
||||
String str =
|
||||
"____ ____ ___ ____ _ _ ____ _ _ \r\n" +
|
||||
"[__ |__| __ | | | |_/ |___ |\\ | \r\n" +
|
||||
"___] | | | |__| | \\_ |___ | \\| \r\n" +
|
||||
"sa-token:" + version + " \r\n" +
|
||||
"GitHub:" + github_url + "\r\n";
|
||||
System.out.println(str);
|
||||
}
|
||||
|
||||
// 如果token为本次请求新创建的,则以此字符串为key存储在当前request中
|
||||
public static final String just_created_save_key= "just_created_save_key_";
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package cn.dev33.satoken.config;
|
||||
|
||||
/**
|
||||
* sa-token 总配置类
|
||||
*/
|
||||
public class SaTokenConfig {
|
||||
|
||||
private String tokenName = "satoken"; // token名称(同时也是cookie名称)
|
||||
private long timeout = 30 * 24 * 60 * 60; // token有效期,单位s 默认30天,-1为永不过期
|
||||
private Boolean isShare = true; // 在多人登录同一账号时,是否共享会话(为true时共用一个,为false时新登录挤掉旧登录)
|
||||
private Boolean isReadHead = false; // 是否在cookie读取不到token时,继续从请求header里继续尝试读取
|
||||
private Boolean isReadBody = false; // 是否在header读取不到token时,继续从请求题参数里继续尝试读取
|
||||
|
||||
private Boolean isV = true; // 是否在初始化配置时打印版本字符画
|
||||
|
||||
|
||||
public String getTokenName() {
|
||||
return tokenName;
|
||||
}
|
||||
public void setTokenName(String tokenName) {
|
||||
this.tokenName = tokenName;
|
||||
}
|
||||
public long getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
public void setTimeout(long timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
public Boolean getIsShare() {
|
||||
return isShare;
|
||||
}
|
||||
public void setIsShare(Boolean isShare) {
|
||||
this.isShare = isShare;
|
||||
}
|
||||
public Boolean getIsReadHead() {
|
||||
return isReadHead;
|
||||
}
|
||||
public void setIsReadHead(Boolean isReadHead) {
|
||||
this.isReadHead = isReadHead;
|
||||
}
|
||||
public Boolean getIsReadBody() {
|
||||
return isReadBody;
|
||||
}
|
||||
public void setIsReadBody(Boolean isReadBody) {
|
||||
this.isReadBody = isReadBody;
|
||||
}
|
||||
public Boolean getIsV() {
|
||||
return isV;
|
||||
}
|
||||
public void setIsV(Boolean isV) {
|
||||
this.isV = isV;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SaTokenConfig [tokenName=" + tokenName + ", timeout=" + timeout + ", isShare=" + isShare
|
||||
+ ", isReadHead=" + isReadHead + ", isReadBody=" + isReadBody + ", isV=" + isV + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
package cn.dev33.satoken.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
创建一个配置文件
|
||||
*/
|
||||
public class SaTokenConfigFactory {
|
||||
|
||||
|
||||
public static String configPath = "sa-token.properties"; // 默认配置文件地址
|
||||
|
||||
/**
|
||||
* 根据指定路径获取配置信息
|
||||
* @return 一个SaTokenConfig对象
|
||||
*/
|
||||
public static SaTokenConfig createConfig() {
|
||||
Map<String, String> map = readPropToMap(configPath);
|
||||
if(map == null){
|
||||
// throw new RuntimeException("找不到配置文件:" + configPath, null);
|
||||
}
|
||||
return (SaTokenConfig)initPropByMap(map, new SaTokenConfig());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 将指定路径的properties配置文件读取到Map中
|
||||
* @param propertiesPath 配置文件地址
|
||||
* @return 一个Map
|
||||
*/
|
||||
private static Map<String, String> readPropToMap(String propertiesPath){
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
try {
|
||||
InputStream is = SaTokenConfigFactory.class.getClassLoader().getResourceAsStream(propertiesPath);
|
||||
if(is == null){
|
||||
return null;
|
||||
}
|
||||
Properties prop = new Properties();
|
||||
prop.load(is);
|
||||
for (String key : prop.stringPropertyNames()) {
|
||||
map.put(key, prop.getProperty(key));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("配置文件(" + propertiesPath + ")加载失败", e);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将 Map 的值映射到 Model 上
|
||||
* @param map 属性集合
|
||||
* @param obj 对象,或类型
|
||||
* @return 返回实例化后的对象
|
||||
*/
|
||||
private static Object initPropByMap(Map<String, String> map, Object obj){
|
||||
|
||||
if(map == null){
|
||||
map = new HashMap<>();
|
||||
}
|
||||
|
||||
// 1、取出类型
|
||||
Class<?> cs = null;
|
||||
if(obj instanceof Class){ // 如果是一个类型,则将obj=null,以便完成静态属性反射赋值
|
||||
cs = (Class<?>)obj;
|
||||
obj = null;
|
||||
}else{ // 如果是一个对象,则取出其类型
|
||||
cs = obj.getClass();
|
||||
}
|
||||
|
||||
// 2、遍历类型属性,反射赋值
|
||||
for (Field field : cs.getDeclaredFields()) {
|
||||
String value = map.get(field.getName());
|
||||
if (value == null) {
|
||||
continue; // 如果为空代表没有配置此项
|
||||
}
|
||||
try {
|
||||
Object valueConvert = getObjectByClass(value, field.getType()); // 转换值类型
|
||||
field.setAccessible(true);
|
||||
field.set(obj, valueConvert);
|
||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||
throw new RuntimeException("属性赋值出错:" + field.getName(), e);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串转化为指定数据类型
|
||||
* @param str 值
|
||||
* @param cs 要转换的类型
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T>T getObjectByClass(String str, Class<T> cs){
|
||||
Object value = null;
|
||||
if(str == null){
|
||||
value = null;
|
||||
}else if (cs.equals(String.class)) {
|
||||
value = str;
|
||||
} else if (cs.equals(int.class)||cs.equals(Integer.class)) {
|
||||
value = new Integer(str);
|
||||
} else if (cs.equals(long.class)||cs.equals(Long.class)) {
|
||||
value = new Long(str);
|
||||
} else if (cs.equals(short.class)||cs.equals(Short.class)) {
|
||||
value = new Short(str);
|
||||
} else if (cs.equals(float.class)||cs.equals(Float.class)) {
|
||||
value = new Float(str);
|
||||
} else if (cs.equals(double.class)||cs.equals(Double.class)) {
|
||||
value = new Double(str);
|
||||
} else if (cs.equals(boolean.class)||cs.equals(Boolean.class)) {
|
||||
value = new Boolean(str);
|
||||
}else{
|
||||
throw new RuntimeException("未能将值:" + str + ",转换类型为:" + cs, null);
|
||||
}
|
||||
return (T)value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package cn.dev33.satoken.dao;
|
||||
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
|
||||
/**
|
||||
* sa-token持久层的接口
|
||||
*/
|
||||
public interface SaTokenDao {
|
||||
|
||||
|
||||
/**
|
||||
* 根据key获取value ,如果没有,则返回空
|
||||
* @param key 键名称
|
||||
* @return
|
||||
*/
|
||||
public String getValue(String key);
|
||||
|
||||
/**
|
||||
* 写入指定key-value键值对,并设定过期时间 (单位:秒)
|
||||
* @param key 键名称
|
||||
* @param value 值
|
||||
* @param timeout 过期时间,单位:s
|
||||
*/
|
||||
public void setValue(String key, String value, long timeout);
|
||||
|
||||
/**
|
||||
* 删除一个指定的key
|
||||
* @param key
|
||||
*/
|
||||
public void delKey(String key);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 根据指定key的session,如果没有,则返回空
|
||||
* @param key 键名称
|
||||
* @return
|
||||
*/
|
||||
public SaSession getSaSession(String sessionId);
|
||||
|
||||
/**
|
||||
* 将指定session持久化
|
||||
* @param key 键名称
|
||||
* @param value 值
|
||||
* @param timeout 过期时间,单位: s
|
||||
*/
|
||||
public void saveSaSession(SaSession session, long timeout);
|
||||
|
||||
/**
|
||||
* 更新指定session
|
||||
*/
|
||||
public void updateSaSession(SaSession session);
|
||||
|
||||
/**
|
||||
* 删除一个指定的session
|
||||
* @param key 键名称
|
||||
*/
|
||||
public void delSaSession(String sessionId);
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package cn.dev33.satoken.dao;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
|
||||
/**
|
||||
* sa-token持久层默认的实现类 , 基于内存Map
|
||||
*/
|
||||
public class SaTokenDaoDefault implements SaTokenDao {
|
||||
|
||||
/**
|
||||
* 所有数据集合
|
||||
*/
|
||||
Map<String, Object> dataMap = new HashMap<String, Object>();
|
||||
|
||||
|
||||
@Override
|
||||
public String getValue(String key) {
|
||||
return (String)dataMap.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(String key, String value, long timeout) {
|
||||
dataMap.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delKey(String key) {
|
||||
dataMap.remove(key);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SaSession getSaSession(String sessionId) {
|
||||
return (SaSession)dataMap.get(sessionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveSaSession(SaSession session, long timeout) {
|
||||
dataMap.put(session.getId(), session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSaSession(SaSession session) {
|
||||
// 无动作
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delSaSession(String sessionId) {
|
||||
dataMap.remove(sessionId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package cn.dev33.satoken.exception;
|
||||
|
||||
/**
|
||||
* 没有登陆抛出的异常
|
||||
*/
|
||||
public class NotLoginException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130142L;
|
||||
|
||||
/**
|
||||
* 创建一个
|
||||
*/
|
||||
public NotLoginException() {
|
||||
super("当前账号未登录");
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package cn.dev33.satoken.exception;
|
||||
|
||||
/**
|
||||
* 没有指定权限码,抛出的异常
|
||||
*/
|
||||
public class NotPermissionException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130142L;
|
||||
|
||||
private Object code;
|
||||
|
||||
|
||||
/**
|
||||
* @return 获得权限码
|
||||
*/
|
||||
public Object getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public NotPermissionException(Object code) {
|
||||
super("无此权限:" + code);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
// public NotPermissionException(Object code, String s) {
|
||||
// super(s);
|
||||
// this.code = code;
|
||||
// }
|
||||
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
package cn.dev33.satoken.session;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
|
||||
|
||||
/**
|
||||
* session会话
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaSession implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String id; // 会话id
|
||||
private long createTime; // 当前会话创建时间
|
||||
private Map<String, Object> dataMap; // 当前会话键值对
|
||||
|
||||
|
||||
/**
|
||||
* 构建一个 session对象
|
||||
* @param id
|
||||
*/
|
||||
public SaSession(String id) {
|
||||
this.id = id;
|
||||
this.createTime = System.currentTimeMillis();
|
||||
this.dataMap = new HashMap<String, Object>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会话id
|
||||
* @return
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前会话创建时间
|
||||
*/
|
||||
public long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入值
|
||||
*/
|
||||
public void setAttribute(String key, Object value) {
|
||||
dataMap.put(key, value);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值
|
||||
*/
|
||||
public Object getAttribute(String key) {
|
||||
return dataMap.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值,并指定取不到值时的默认值
|
||||
*/
|
||||
public Object getAttribute(String key, Object default_value) {
|
||||
Object value = getAttribute(key);
|
||||
if(value != null) {
|
||||
return value;
|
||||
}
|
||||
return default_value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 移除一个key
|
||||
*/
|
||||
public void removeAttribute(String key) {
|
||||
dataMap.remove(key);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有key
|
||||
*/
|
||||
public void clearAttribute() {
|
||||
dataMap.clear();
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否含有指定key
|
||||
*/
|
||||
public boolean containsAttribute(String key) {
|
||||
return dataMap.keySet().contains(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前session会话所有key
|
||||
*/
|
||||
public Set<String> getAttributeKeys() {
|
||||
return dataMap.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据集合(如果更新map里的值,请调用session.update()方法避免数据过时 )
|
||||
*/
|
||||
public Map<String, Object> getDataMap() {
|
||||
return dataMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将这个session从持久库更新一下
|
||||
*/
|
||||
public void update() {
|
||||
SaTokenManager.getDao().updateSaSession(this);
|
||||
}
|
||||
|
||||
|
||||
// /** 注销会话(注销后,此session会话将不再存储服务器上) */
|
||||
// public void logout() {
|
||||
// SaTokenManager.getDao().delSaSession(this.id);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package cn.dev33.satoken.session;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
|
||||
/**
|
||||
* sa-session工具类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaSessionUtil {
|
||||
|
||||
// 添加上指定前缀,防止恶意伪造session
|
||||
public static String session_key = "custom";
|
||||
public static String getSessionKey(String sessionId) {
|
||||
return SaTokenManager.getConfig().getTokenName() + ":" + session_key + ":session:" + sessionId;
|
||||
}
|
||||
|
||||
/** 指定key的session是否存在 */
|
||||
public boolean isExists(String sessionId) {
|
||||
return SaTokenManager.getDao().getSaSession(getSessionKey(sessionId)) != null;
|
||||
}
|
||||
|
||||
/** 获取指定key的session, 如果没有,is_create=是否新建并返回 */
|
||||
public static SaSession getSessionById(String sessionId, boolean is_create) {
|
||||
SaSession session = SaTokenManager.getDao().getSaSession(getSessionKey(sessionId));
|
||||
if(session == null && is_create) {
|
||||
session = new SaSession(getSessionKey(sessionId));
|
||||
SaTokenManager.getDao().saveSaSession(session, SaTokenManager.getConfig().getTimeout());
|
||||
}
|
||||
return session;
|
||||
}
|
||||
/** 获取指定key的session, 如果没有则新建并返回 */
|
||||
public static SaSession getSessionById(String sessionId) {
|
||||
return getSessionById(sessionId, true);
|
||||
}
|
||||
|
||||
/** 删除指定key的session */
|
||||
public static void delSessionById(String sessionId) {
|
||||
SaTokenManager.getDao().delSaSession(getSessionKey(sessionId));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package cn.dev33.satoken.spring;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* 将此注解加到springboot启动类上,即可完成sa-token与springboot的集成
|
||||
*/
|
||||
@Documented
|
||||
@Target({java.lang.annotation.ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Configuration
|
||||
@Import({SpringSaToken.class})
|
||||
public @interface SaTokenSetup {
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package cn.dev33.satoken.spring;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
|
||||
/**
|
||||
* 与SpringBoot集成, 保证此类被扫描,即可完成sa-token与SpringBoot的集成
|
||||
* @author kongyongshun
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class SpringSaToken {
|
||||
|
||||
|
||||
// 获取配置Bean
|
||||
@Bean
|
||||
@ConfigurationProperties(prefix="spring.sa-token")
|
||||
public SaTokenConfig getSaTokenConfig() {
|
||||
return new SaTokenConfig();
|
||||
}
|
||||
|
||||
// 注入配置Bean
|
||||
@Autowired
|
||||
public void setConfig(SaTokenConfig saTokenConfig){
|
||||
SaTokenManager.setConfig(saTokenConfig);
|
||||
}
|
||||
|
||||
// 注入持久化Bean
|
||||
@Autowired(required = false)
|
||||
public void setDao(SaTokenDao dao){
|
||||
SaTokenManager.setDao(dao);
|
||||
}
|
||||
|
||||
// 注入权限认证Bean
|
||||
@Autowired(required = false)
|
||||
public void setStp(StpInterface stp){
|
||||
SaTokenManager.setStp(stp);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package cn.dev33.satoken.stp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 开放权限验证接口,方便重写
|
||||
*/
|
||||
public interface StpInterface {
|
||||
|
||||
/** 返回指定login_id所拥有的权限码集合 */
|
||||
public List<Object> getPermissionCodeList(Object login_id, String login_key);
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package cn.dev33.satoken.stp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 权限验证接口 ,默认实现
|
||||
*/
|
||||
public class StpInterfaceDefaultImpl implements StpInterface {
|
||||
|
||||
@Override
|
||||
public List<Object> getPermissionCodeList(Object login_id, String login_key) {
|
||||
return new ArrayList<Object>();
|
||||
}
|
||||
|
||||
}
|
306
sa-token-dev/src/main/java/cn/dev33/satoken/stp/StpLogic.java
Normal file
306
sa-token-dev/src/main/java/cn/dev33/satoken/stp/StpLogic.java
Normal file
@ -0,0 +1,306 @@
|
||||
package cn.dev33.satoken.stp;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.SaTokenUtil;
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.exception.NotPermissionException;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.util.SaCookieUtil;
|
||||
import cn.dev33.satoken.util.SpringMVCUtil;
|
||||
|
||||
/**
|
||||
* sa-token 权限验证,逻辑 实现类
|
||||
* <p>
|
||||
* (stp = sa-token-permission 的缩写 )
|
||||
*
|
||||
*/
|
||||
public class StpLogic {
|
||||
|
||||
|
||||
private String login_key = ""; // 持久化的key前缀,多账号体系时以此值区分,比如:login、user、admin
|
||||
|
||||
public StpLogic(String login_key) {
|
||||
this.login_key = login_key;
|
||||
}
|
||||
|
||||
// =================== 获取token 相关 ===================
|
||||
|
||||
|
||||
/** 随机生成一个tokenValue */
|
||||
public String randomTokenValue() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
/** 获取当前tokenValue */
|
||||
public String getTokenValue(){
|
||||
// 0、获取相应对象
|
||||
HttpServletRequest request = SpringMVCUtil.getRequest();
|
||||
SaTokenConfig config = SaTokenManager.getConfig();
|
||||
String key_tokenName = getKey_tokenName();
|
||||
|
||||
// 1、尝试从request里读取
|
||||
if(request.getAttribute(SaTokenUtil.just_created_save_key) != null) {
|
||||
return String.valueOf(request.getAttribute(SaTokenUtil.just_created_save_key));
|
||||
}
|
||||
|
||||
// 2、尝试从cookie里读取
|
||||
Cookie cookie = SaCookieUtil.getCookie(request, key_tokenName);
|
||||
if(cookie != null){
|
||||
String tokenValue = cookie.getValue();
|
||||
if(tokenValue != null) {
|
||||
return tokenValue;
|
||||
}
|
||||
}
|
||||
|
||||
// 3、尝试从header力读取
|
||||
if(config.getIsReadHead() == true){
|
||||
String tokenValue = request.getHeader(key_tokenName);
|
||||
if(tokenValue != null) {
|
||||
return tokenValue;
|
||||
}
|
||||
}
|
||||
|
||||
// 4、尝试从请求体里面读取
|
||||
if(config.getIsReadBody() == true){
|
||||
String tokenValue = request.getParameter(key_tokenName);
|
||||
if(tokenValue != null) {
|
||||
return tokenValue;
|
||||
}
|
||||
}
|
||||
|
||||
// 5、都读取不到,那算了吧还是
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 获取指定id的tokenValue */
|
||||
public String getTokenValueByLoginId(Object login_id) {
|
||||
return SaTokenManager.getDao().getValue(getKey_LoginId(login_id));
|
||||
}
|
||||
|
||||
/** 获取当前会话的token信息:tokenName与tokenValue */
|
||||
public Map<String, String> getTokenInfo() {
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
map.put("tokenName", getKey_tokenName());
|
||||
map.put("tokenValue", getTokenValue());
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
// =================== 登录相关操作 ===================
|
||||
|
||||
/** 在当前会话上登录id ,建议的类型:(long | int | String) */
|
||||
public void setLoginId(Object login_id) {
|
||||
|
||||
// 1、获取相应对象
|
||||
HttpServletRequest request = SpringMVCUtil.getRequest();
|
||||
SaTokenConfig config = SaTokenManager.getConfig();
|
||||
SaTokenDao dao = SaTokenManager.getDao();
|
||||
|
||||
// 2、获取tokenValue
|
||||
String tokenValue = getTokenValueByLoginId(login_id); // 获取旧tokenValue
|
||||
if(tokenValue == null){ // 为null则创建一个新的
|
||||
tokenValue = randomTokenValue();
|
||||
} else {
|
||||
// 不为null, 并且配置不共享,则删掉原来,并且创建新的
|
||||
if(config.getIsShare() == false){
|
||||
dao.delKey(getKey_TokenValue(tokenValue));
|
||||
tokenValue = randomTokenValue();
|
||||
}
|
||||
}
|
||||
|
||||
// 3、持久化
|
||||
dao.setValue(getKey_TokenValue(tokenValue), String.valueOf(login_id), config.getTimeout()); // token -> uid
|
||||
dao.setValue(getKey_LoginId(login_id), tokenValue, config.getTimeout()); // uid -> token
|
||||
request.setAttribute(SaTokenUtil.just_created_save_key, tokenValue); // 保存到本次request里
|
||||
SaCookieUtil.addCookie(SpringMVCUtil.getResponse(), getKey_tokenName(), tokenValue, "/", (int)config.getTimeout()); // cookie注入
|
||||
}
|
||||
|
||||
/** 当前会话注销登录 */
|
||||
public void logout() {
|
||||
Object login_id = getLoginId_defaultNull();
|
||||
if(login_id != null) {
|
||||
logoutByLoginId(login_id);
|
||||
SaCookieUtil.delCookie(SpringMVCUtil.getRequest(), SpringMVCUtil.getResponse(), getKey_tokenName()); // 清除cookie
|
||||
}
|
||||
}
|
||||
|
||||
/** 指定login_id的会话注销登录(踢人下线) */
|
||||
public void logoutByLoginId(Object login_id) {
|
||||
|
||||
// 获取相应tokenValue
|
||||
String tokenValue = getTokenValueByLoginId(login_id);
|
||||
if(tokenValue == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 清除相关数据
|
||||
SaTokenManager.getDao().delKey(getKey_TokenValue(tokenValue)); // 清除token-id键值对
|
||||
SaTokenManager.getDao().delKey(getKey_LoginId(login_id)); // 清除id-token键值对
|
||||
SaTokenManager.getDao().delKey(getKey_session(login_id)); // 清除其session
|
||||
// SaCookieUtil.delCookie(SpringMVCUtil.getRequest(), SpringMVCUtil.getResponse(), getKey_tokenName()); // 清除cookie
|
||||
}
|
||||
|
||||
// 查询相关
|
||||
|
||||
/** 获取当前会话是否已经登录 */
|
||||
public boolean isLogin() {
|
||||
return getLoginId_defaultNull() != null;
|
||||
}
|
||||
|
||||
/** 获取当前会话登录id, 如果未登录,则抛出异常 */
|
||||
public Object getLoginId() {
|
||||
Object login_id = getLoginId_defaultNull();
|
||||
if(login_id == null) {
|
||||
throw new NotLoginException();
|
||||
}
|
||||
return login_id;
|
||||
}
|
||||
|
||||
/** 获取当前会话登录id, 如果未登录,则返回默认值 */
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T>T getLoginId(T default_value) {
|
||||
Object login_id = getLoginId_defaultNull();
|
||||
if(login_id == null) {
|
||||
return default_value;
|
||||
}
|
||||
return (T)login_id;
|
||||
}
|
||||
|
||||
/** 获取当前会话登录id, 如果未登录,则返回null */
|
||||
public Object getLoginId_defaultNull() {
|
||||
String tokenValue = getTokenValue();
|
||||
if(tokenValue != null) {
|
||||
Object login_id = SaTokenManager.getDao().getValue(getKey_TokenValue(tokenValue));
|
||||
if(login_id != null) {
|
||||
return login_id;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 获取当前会话登录id, 并转换为String */
|
||||
public String getLoginId_asString() {
|
||||
return String.valueOf(getLoginId());
|
||||
}
|
||||
|
||||
/** 获取当前会话登录id, 并转换为int */
|
||||
public int getLoginId_asInt() {
|
||||
// Object login_id = getLoginId();
|
||||
// if(login_id instanceof Integer) {
|
||||
// return (Integer)login_id;
|
||||
// }
|
||||
return Integer.valueOf(String.valueOf(getLoginId()));
|
||||
}
|
||||
|
||||
/** 获取当前会话登录id, 并转换为long */
|
||||
public long getLoginId_asLong() {
|
||||
// Object login_id = getLoginId();
|
||||
// if(login_id instanceof Long) {
|
||||
// return (Long)login_id;
|
||||
// }
|
||||
return Long.valueOf(String.valueOf(getLoginId()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =================== session相关 ===================
|
||||
|
||||
/** 获取指定key的session, 如果没有,is_create=是否新建并返回 */
|
||||
protected SaSession getSessionBySessionId(String sessionId, boolean is_create) {
|
||||
SaSession session = SaTokenManager.getDao().getSaSession(sessionId);
|
||||
if(session == null && is_create) {
|
||||
session = new SaSession(sessionId);
|
||||
SaTokenManager.getDao().saveSaSession(session, SaTokenManager.getConfig().getTimeout());
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
/** 获取指定login_id的session */
|
||||
public SaSession getSessionByLoginId(Object login_id) {
|
||||
return getSessionBySessionId(getKey_session(login_id), false);
|
||||
}
|
||||
|
||||
/** 获取当前会话的session */
|
||||
public SaSession getSession() {
|
||||
return getSessionBySessionId(getKey_session(getLoginId()), true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =================== 权限验证操作 ===================
|
||||
|
||||
/** 指定login_id是否含有指定权限 */
|
||||
public boolean hasPermission(Object login_id, Object pcode) {
|
||||
List<Object> pcodeList = SaTokenManager.getStp().getPermissionCodeList(login_id, login_key);
|
||||
return !(pcodeList == null || pcodeList.contains(pcode) == false);
|
||||
}
|
||||
|
||||
/** 当前会话是否含有指定权限 */
|
||||
public boolean hasPermission(Object pcode) {
|
||||
return hasPermission(getLoginId(), pcode);
|
||||
}
|
||||
|
||||
/** 当前账号是否含有指定权限 , 没有就抛出异常 */
|
||||
public void checkPermission(Object pcode) {
|
||||
if(hasPermission(pcode) == false) {
|
||||
throw new NotPermissionException(pcode);
|
||||
}
|
||||
}
|
||||
|
||||
/** 当前账号是否含有指定权限 , 【指定多个,必须全都有】 */
|
||||
public void checkPermissionAnd(Object... pcodeArray){
|
||||
Object login_id = getLoginId();
|
||||
List<Object> pcodeList = SaTokenManager.getStp().getPermissionCodeList(login_id, login_key);
|
||||
for (Object pcode : pcodeArray) {
|
||||
if(pcodeList.contains(pcode) == false) {
|
||||
throw new NotPermissionException(pcode); // 没有权限抛出异常
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 当前账号是否含有指定权限 , 【指定多个,有一个就可以了】 */
|
||||
public void checkPermissionOr(Object... pcodeArray){
|
||||
Object login_id = getLoginId();
|
||||
List<Object> pcodeList = SaTokenManager.getStp().getPermissionCodeList(login_id, login_key);
|
||||
for (Object pcode : pcodeArray) {
|
||||
if(pcodeList.contains(pcode) == true) {
|
||||
return; // 有的话提前退出
|
||||
}
|
||||
}
|
||||
if(pcodeArray.length > 0) {
|
||||
throw new NotPermissionException(pcodeArray[0]); // 没有权限抛出异常
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// =================== 返回相应key ===================
|
||||
|
||||
/** 获取key:客户端 tokenName */
|
||||
public String getKey_tokenName() {
|
||||
return SaTokenManager.getConfig().getTokenName();
|
||||
}
|
||||
/** 获取key: tokenValue 持久化 */
|
||||
public String getKey_TokenValue(String tokenValue) {
|
||||
return SaTokenManager.getConfig().getTokenName() + ":" + login_key + ":token:" + tokenValue;
|
||||
}
|
||||
/** 获取key: id 持久化 */
|
||||
public String getKey_LoginId(Object login_id) {
|
||||
return SaTokenManager.getConfig().getTokenName() + ":" + login_key + ":id:" + login_id;
|
||||
}
|
||||
/** 获取key: session 持久化 */
|
||||
public String getKey_session(Object login_id) {
|
||||
return SaTokenManager.getConfig().getTokenName() + ":" + login_key + ":session:" + login_id;
|
||||
}
|
||||
|
||||
|
||||
}
|
131
sa-token-dev/src/main/java/cn/dev33/satoken/stp/StpUtil.java
Normal file
131
sa-token-dev/src/main/java/cn/dev33/satoken/stp/StpUtil.java
Normal file
@ -0,0 +1,131 @@
|
||||
package cn.dev33.satoken.stp;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
|
||||
/**
|
||||
* 一个默认的实现
|
||||
*/
|
||||
@Service
|
||||
public class StpUtil {
|
||||
|
||||
// 底层的 StpLogic 对象
|
||||
public static StpLogic stpLogic = new StpLogic("login");
|
||||
|
||||
|
||||
// =================== 获取token 相关 ===================
|
||||
|
||||
|
||||
/** 获取当前tokenValue */
|
||||
public static String getTokenValue() {
|
||||
return stpLogic.getTokenValue();
|
||||
}
|
||||
|
||||
/** 获取指定id的tokenValue */
|
||||
public static String getTokenValueByLoginId(Object login_id) {
|
||||
return stpLogic.getTokenValueByLoginId(login_id);
|
||||
}
|
||||
|
||||
/** 获取当前会话的token信息:tokenName与tokenValue */
|
||||
public static Map<String, String> getTokenInfo() {
|
||||
return stpLogic.getTokenInfo();
|
||||
}
|
||||
|
||||
// =================== 登录相关操作 ===================
|
||||
|
||||
/** 在当前会话上设置登录id,建议的类型:(long | int | String) */
|
||||
public static void setLoginId(Object login_id) {
|
||||
stpLogic.setLoginId(login_id);
|
||||
}
|
||||
|
||||
/** 当前会话注销登录 */
|
||||
public static void logout() {
|
||||
stpLogic.logout();
|
||||
}
|
||||
|
||||
/** 指定login_id的会话注销登录(踢人下线) */
|
||||
public static void logoutByLoginId(Object login_id) {
|
||||
stpLogic.logoutByLoginId(login_id);
|
||||
}
|
||||
|
||||
// 查询相关
|
||||
|
||||
/** 获取当前会话是否已经登录 */
|
||||
public static boolean isLogin() {
|
||||
return stpLogic.isLogin();
|
||||
}
|
||||
|
||||
/** 获取当前会话登录id, 如果未登录,则抛出异常 */
|
||||
public static Object getLoginId() {
|
||||
return stpLogic.getLoginId();
|
||||
}
|
||||
|
||||
/** 获取当前会话登录id, 如果未登录,则返回默认值 */
|
||||
public static <T> T getLoginId(T default_value) {
|
||||
return stpLogic.getLoginId(default_value);
|
||||
}
|
||||
|
||||
/** 获取当前会话登录id, 如果未登录,则返回null */
|
||||
public static Object getLoginId_defaultNull() {
|
||||
return stpLogic.getLoginId_defaultNull();
|
||||
}
|
||||
|
||||
/** 获取当前会话登录id, 并转换为String */
|
||||
public static String getLoginId_asString() {
|
||||
return stpLogic.getLoginId_asString();
|
||||
}
|
||||
|
||||
/** 获取当前会话登录id, 并转换为int */
|
||||
public static int getLoginId_asInt() {
|
||||
return stpLogic.getLoginId_asInt();
|
||||
}
|
||||
|
||||
/** 获取当前会话登录id, 并转换为long */
|
||||
public static long getLoginId_asLong() {
|
||||
return stpLogic.getLoginId_asLong();
|
||||
}
|
||||
|
||||
// =================== session相关 ===================
|
||||
|
||||
/** 获取指定login_id的session */
|
||||
public static SaSession getSessionByLoginId(Object login_id) {
|
||||
return stpLogic.getSessionByLoginId(login_id);
|
||||
}
|
||||
|
||||
/** 获取当前会话的session */
|
||||
public static SaSession getSession() {
|
||||
return stpLogic.getSession();
|
||||
}
|
||||
|
||||
// =================== 权限验证操作 ===================
|
||||
|
||||
/** 指定login_id是否含有指定权限 */
|
||||
public static boolean hasPermission(Object login_id, Object pcode) {
|
||||
return stpLogic.hasPermission(login_id, pcode);
|
||||
}
|
||||
|
||||
/** 当前会话是否含有指定权限 */
|
||||
public static boolean hasPermission(Object pcode) {
|
||||
return stpLogic.hasPermission(pcode);
|
||||
}
|
||||
|
||||
/** 当前账号是否含有指定权限 , 没有就抛出异常 */
|
||||
public static void checkPermission(Object pcode) {
|
||||
stpLogic.checkPermission(pcode);
|
||||
}
|
||||
|
||||
/** 当前账号是否含有指定权限 , 【指定多个,必须全都有】 */
|
||||
public static void checkPermissionAnd(Object... pcodeArray) {
|
||||
stpLogic.checkPermissionAnd(pcodeArray);
|
||||
}
|
||||
|
||||
/** 当前账号是否含有指定权限 , 【指定多个,有一个就可以了】 */
|
||||
public static void checkPermissionOr(Object... pcodeArray) {
|
||||
stpLogic.checkPermissionOr(pcodeArray);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package cn.dev33.satoken.util;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
/**
|
||||
* cookie工具类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaCookieUtil {
|
||||
|
||||
|
||||
/**
|
||||
* 获取指定cookie
|
||||
*/
|
||||
public static Cookie getCookie(HttpServletRequest request, String cookieName) {
|
||||
Cookie[] cookies = request.getCookies();
|
||||
if(cookies != null) {
|
||||
for(int i = 0; i < cookies.length; i++) {
|
||||
Cookie cookie = cookies[i];
|
||||
if(cookie != null && cookieName.equals(cookie.getName())) {
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加cookie
|
||||
*/
|
||||
public static void addCookie(HttpServletResponse response,String name,String value,String path,int timeout) {
|
||||
Cookie cookie = new Cookie(name, value);
|
||||
if(path == null) {
|
||||
path = "/";
|
||||
}
|
||||
cookie.setPath(path);
|
||||
cookie.setMaxAge(timeout);
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除cookie
|
||||
*/
|
||||
public static void delCookie(HttpServletRequest request,HttpServletResponse response,String name) {
|
||||
Cookie[] cookies = request.getCookies();
|
||||
if(cookies != null){
|
||||
for(Cookie cookie : cookies) {
|
||||
if(cookies != null && (name).equals(cookie.getName())) {
|
||||
addCookie(response,name,null,null,0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 修改cookie的value值
|
||||
*/
|
||||
public static void updateCookie(HttpServletRequest request,HttpServletResponse response,String name,String value) {
|
||||
Cookie[] cookies = request.getCookies();
|
||||
if(cookies != null){
|
||||
for(Cookie cookie : cookies) {
|
||||
if(cookies != null && (name).equals(cookie.getName())) {
|
||||
addCookie(response,name,value,cookie.getPath(),cookie.getMaxAge());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package cn.dev33.satoken.util;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
/**
|
||||
* SpringMVC相关操作
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SpringMVCUtil {
|
||||
|
||||
// 获取当前会话的 request
|
||||
public static HttpServletRequest getRequest() {
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();// 大善人SpringMVC提供的封装
|
||||
if(servletRequestAttributes == null) {
|
||||
throw new RuntimeException("当前环境非JavaWeb");
|
||||
}
|
||||
return servletRequestAttributes.getRequest();
|
||||
}
|
||||
|
||||
// 获取当前会话的
|
||||
public static HttpServletResponse getResponse() {
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();// 大善人SpringMVC提供的封装
|
||||
if(servletRequestAttributes == null) {
|
||||
throw new RuntimeException("当前环境非JavaWeb");
|
||||
}
|
||||
return servletRequestAttributes.getResponse();
|
||||
}
|
||||
|
||||
}
|
18
sa-token-dev/src/main/java/com/pj/SaTokenApplication.java
Normal file
18
sa-token-dev/src/main/java/com/pj/SaTokenApplication.java
Normal file
@ -0,0 +1,18 @@
|
||||
package com.pj;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.spring.SaTokenSetup;
|
||||
|
||||
@SaTokenSetup // 标注启动 sa-token
|
||||
@SpringBootApplication
|
||||
public class SaTokenApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SaTokenApplication.class, args); // run-->
|
||||
System.out.println(SaTokenManager.getConfig());
|
||||
}
|
||||
|
||||
}
|
20
sa-token-dev/src/main/resources/application.yml
Normal file
20
sa-token-dev/src/main/resources/application.yml
Normal file
@ -0,0 +1,20 @@
|
||||
# 端口
|
||||
server:
|
||||
port: 8081
|
||||
|
||||
spring:
|
||||
# sa-token配置
|
||||
sa-token:
|
||||
# token名称(同时也是cookie名称)
|
||||
token-name: satoken
|
||||
# token有效期,单位s 默认30天,-1为永不过期
|
||||
timeout: 2592000
|
||||
# 在多人登录同一账号时,是否共享会话(为true时共用一个,为false时新登录挤掉旧登录)
|
||||
is-share: true
|
||||
# 是否在cookie读取不到token时,继续从请求header里继续尝试读取
|
||||
is-read-head: true
|
||||
# 是否在header读取不到token时,继续从请求题参数里继续尝试读取
|
||||
is-read-body: true
|
||||
# 是否在初始化配置时打印版本字符画
|
||||
is-v: true
|
||||
|
11
sa-token-doc/index.html
Normal file
11
sa-token-doc/index.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>sa-token在线文档</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>sa-token在线文档</h1>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user