mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-09-19 01:58:05 +08:00
单点登录:CAS模式
This commit is contained in:
12
sa-token-demo/sa-token-demo-sso-server/.gitignore
vendored
Normal file
12
sa-token-demo/sa-token-demo-sso-server/.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
target/
|
||||
|
||||
node_modules/
|
||||
bin/
|
||||
.settings/
|
||||
unpackage/
|
||||
.classpath
|
||||
.project
|
||||
|
||||
.idea/
|
||||
|
||||
.factorypath
|
53
sa-token-demo/sa-token-demo-sso-server/pom.xml
Normal file
53
sa-token-demo/sa-token-demo-sso-server/pom.xml
Normal file
@@ -0,0 +1,53 @@
|
||||
<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-sso-server</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>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<!-- 定义sa-token版本号 -->
|
||||
<properties>
|
||||
<sa-token-version>1.20.0</sa-token-version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- springboot依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token 权限认证, 在线文档:http://sa-token.dev33.cn/ -->
|
||||
<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>
|
||||
|
||||
<!-- 提供redis连接池 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
@@ -0,0 +1,21 @@
|
||||
package com.pj;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
|
||||
/**
|
||||
* Sa-Token整合SpringBoot 示例
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class SaSsoServerApplication {
|
||||
|
||||
public static void main(String[] args) throws ClassNotFoundException {
|
||||
SpringApplication.run(SaSsoServerApplication.class, args);
|
||||
System.out.println("\nSa-Token-SSO 服务端启动成功:Sa-Token配置如下:" + SaManager.getConfig());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package com.pj.sso;
|
||||
|
||||
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.ResponseBody;
|
||||
|
||||
import com.pj.util.AjaxJson;
|
||||
|
||||
/**
|
||||
* 全局异常处理
|
||||
*/
|
||||
@ControllerAdvice // 可指定包前缀,比如:(basePackages = "com.pj.admin")
|
||||
public class GlobalException {
|
||||
|
||||
// 全局异常拦截(拦截项目中的所有异常)
|
||||
@ResponseBody
|
||||
@ExceptionHandler
|
||||
public AjaxJson handlerException(Exception e, HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception {
|
||||
|
||||
// 打印堆栈,以供调试
|
||||
System.out.println("全局异常---------------");
|
||||
e.printStackTrace();
|
||||
|
||||
// 不同异常返回不同状态码
|
||||
AjaxJson aj = AjaxJson.getError(e.getMessage());
|
||||
|
||||
// 返回给前端
|
||||
return aj;
|
||||
|
||||
// 输出到客户端
|
||||
// response.setContentType("application/json; charset=utf-8"); // http说明,我要返回JSON对象
|
||||
// response.getWriter().print(new ObjectMapper().writeValueAsString(aj));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
package com.pj.sso;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import com.pj.util.AjaxJson;
|
||||
|
||||
import cn.dev33.satoken.sso.SaSsoUtil;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
|
||||
/**
|
||||
* Sa-Token-SSO Server端 Controller
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
public class SsoServerController {
|
||||
|
||||
// SSO-Server端:授权地址,跳转到登录页面
|
||||
@RequestMapping("ssoAuth")
|
||||
public Object ssoAuth(String redirect) {
|
||||
/*
|
||||
* 两种情况分开处理:
|
||||
* 1、如果在SSO认证中心尚未登录,则先去登登录
|
||||
* 2、如果在SSO认证中心尚已登录,则开始对redirect地址下放ticket引导授权
|
||||
*/
|
||||
// 情况1:尚未登录
|
||||
if(StpUtil.isLogin() == false) {
|
||||
String msg = "当前会话在SSO-Server端尚未登录,请先访问"
|
||||
+ "<a href='/doLogin?name=sa&pwd=123456' target='_blank'> doLogin登录 </a>"
|
||||
+ "进行登录之后,刷新页面开始授权";
|
||||
return msg;
|
||||
}
|
||||
// 情况2:已经登录,开始构建授权重定向地址,下放ticket
|
||||
String redirectUrl = SaSsoUtil.buildRedirectUrl(StpUtil.getLoginId(), redirect);
|
||||
return new ModelAndView("redirect:" + redirectUrl);
|
||||
}
|
||||
|
||||
// SSO-Server端:登录接口
|
||||
@RequestMapping("doLogin")
|
||||
public AjaxJson doLogin(String name, String pwd) {
|
||||
if("sa".equals(name) && "123456".equals(pwd)) {
|
||||
StpUtil.login(10001);
|
||||
return AjaxJson.getSuccess("登录成功!");
|
||||
}
|
||||
return AjaxJson.getError("登录失败!");
|
||||
}
|
||||
|
||||
// SSO-Server端:根据 Ticket 获取账号id
|
||||
@RequestMapping("getLoginId")
|
||||
public AjaxJson getLoginId(String ticket) {
|
||||
Object loginId = SaSsoUtil.getLoginId(ticket);
|
||||
if(loginId != null) {
|
||||
SaSsoUtil.deleteTicket(ticket);
|
||||
return AjaxJson.getSuccessData(loginId);
|
||||
}
|
||||
return AjaxJson.getError("无效ticket: " + ticket);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,162 @@
|
||||
package com.pj.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* ajax请求返回Json格式数据的封装
|
||||
*/
|
||||
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,46 @@
|
||||
# 端口
|
||||
server:
|
||||
port: 9000
|
||||
|
||||
spring:
|
||||
# Sa-Token配置
|
||||
sa-token:
|
||||
# Token名称
|
||||
token-name: satoken
|
||||
# Token有效期
|
||||
timeout: 2592000
|
||||
# Token风格
|
||||
token-style: uuid
|
||||
# SSO单点登录-相关配置
|
||||
# sso:
|
||||
# allow-url: http*
|
||||
|
||||
|
||||
# redis配置
|
||||
redis:
|
||||
# Redis数据库索引(默认为0)
|
||||
database: 0
|
||||
# Redis服务器地址
|
||||
host: 127.0.0.1
|
||||
# Redis服务器连接端口
|
||||
port: 6379
|
||||
# Redis服务器连接密码(默认为空)
|
||||
password:
|
||||
# 连接超时时间(毫秒)
|
||||
timeout: 10ms
|
||||
lettuce:
|
||||
pool:
|
||||
# 连接池最大连接数
|
||||
max-active: 200
|
||||
# 连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
max-wait: -1ms
|
||||
# 连接池中的最大空闲连接
|
||||
max-idle: 10
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user