简化单点登录集成步骤

This commit is contained in:
click33
2021-07-08 01:24:42 +08:00
parent 82f7d7f78c
commit 922e746eb1
33 changed files with 790 additions and 1136 deletions

View File

@@ -2,10 +2,8 @@ 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 cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.sso.SaSsoUtil;
import cn.dev33.satoken.sso.SaSsoHandle;
import cn.dev33.satoken.stp.StpUtil;
/**
@@ -20,40 +18,16 @@ public class SsoClientController {
public String index() {
String str = "<h2>Sa-Token SSO-Client 应用端</h2>" +
"<p>当前会话是否登录:" + StpUtil.isLogin() + "</p>" +
"<p><a href=\"javascript:location.href='/ssoLogin?back=' + encodeURIComponent(location.href);\">登录</a></p>";
"<p><a href=\"javascript:location.href='/ssoLogin?back=' + encodeURIComponent(location.href);\">登录</a> " +
"<a href=\"javascript:location.href='/ssoLogout?back=' + encodeURIComponent(location.href);\">注销</a></p>";
// "<a href='/ssoLogout' target='_blank'>注销</a></p>"; // 上面是[跳页面]方式,这个是[RestAPI]方式 区别在于是否加了back参数
return str;
}
// SSO-Client端登录地址
@RequestMapping("ssoLogin")
public Object ssoLogin(String back, String ticket) {
// 如果当前Client端已经登录则无需访问SSO认证中心可以直接返回
if(StpUtil.isLogin()) {
return new ModelAndView("redirect:" + back);
}
/*
* 接下来两种情况:
* ticket无值说明此请求是Client端访问需要重定向至SSO认证中心
* ticket有值说明此请求从SSO认证中心重定向而来需要根据ticket进行登录
*/
if(ticket == null) {
String serverAuthUrl = SaSsoUtil.buildServerAuthUrl(SaHolder.getRequest().getUrl(), back);
return new ModelAndView("redirect:" + serverAuthUrl);
} else {
Object loginId = checkTicket(ticket);
if(loginId != null ) {
// loginId有值说明ticket有效
StpUtil.login(loginId);
return new ModelAndView("redirect:" + back);
}
// 此处向客户端提示ticket无效即可不要重定向到SSO认证中心否则容易引起无限重定向
return "ticket无效: " + ticket;
}
}
// SSO-Client端校验ticket获取账号id
private Object checkTicket(String ticket) {
return SaSsoUtil.checkTicket(ticket);
// SSO-Client端处理所有SSO相关请求
@RequestMapping("/sso*")
public Object ssoRequest() {
return SaSsoHandle.clientRequest();
}
}

View File

@@ -1,162 +0,0 @@
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=okfalse=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
+ "}";
}
}

View File

@@ -14,6 +14,8 @@ sa-token:
sso:
# SSO-Server端 单点登录地址
auth-url: http://sa-sso-server.com:9000/ssoAuth
# 是否打开单点注销接口
is-slo: true
# 配置Sa-Token单独使用的Redis连接 此处需要和SSO-Server端连接同一个Redis
alone-redis:

View File

@@ -3,19 +3,19 @@ package com.pj.sso;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.pj.util.AjaxJson;
import cn.dev33.satoken.util.SaResult;
/**
* 全局异常处理
*/
@RestControllerAdvice
public class GlobalException {
public class ExceptionHandle {
// 全局异常拦截拦截项目中的所有异常
// 全局异常拦截
@ExceptionHandler
public AjaxJson handlerException(Exception e){
public SaResult handlerException(Exception e) {
e.printStackTrace();
return AjaxJson.getError(e.getMessage());
return SaResult.error(e.getMessage());
}
}

View File

@@ -1,13 +1,14 @@
package com.pj.sso;
import org.springframework.beans.factory.annotation.Autowired;
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.config.SaTokenConfig;
import cn.dev33.satoken.sso.SaSsoHandle;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
/**
* Sa-Token-SSO Server端 Controller
@@ -17,33 +18,30 @@ import cn.dev33.satoken.stp.StpUtil;
@RestController
public class SsoServerController {
// SSO-Server端授权地址,跳转到登录页面
@RequestMapping("ssoAuth")
public Object ssoAuth(String redirect) {
/*
* 此处两种情况分开处理:
* 1、如果在SSO认证中心尚未登录则先去登登录
* 2、如果在SSO认证中心尚已登录则开始对redirect地址下放ticket引导授权
*/
// 情况1尚未登录
if(StpUtil.isLogin() == false) {
// return "当前会话在SSO-Server端尚未登录请先访问<a href='/doLogin?name=sa&pwd=123456' target='_blank'> doLogin登录 </a>进行登录之后,刷新页面开始授权";
return new ModelAndView("sa-login.html");
}
// 情况2已经登录开始构建授权重定向地址下放ticket
String redirectUrl = SaSsoUtil.buildRedirectUrl(StpUtil.getLoginId(), redirect);
return new ModelAndView("redirect:" + redirectUrl);
// SSO-Server端处理所有SSO相关请求
@RequestMapping("/sso*")
public Object ssoRequest() {
return SaSsoHandle.serverRequest();
}
// 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相关参数
@Autowired
private void configSso(SaTokenConfig cfg) {
cfg.sso
// 配置未登录时返回的View
.setNotLoginView(() -> {
return new ModelAndView("sa-login.html");
})
// 配置:登录处理函数
.setDoLoginHandle((name, pwd) -> {
// 此处仅做模拟登录,真实环境应该查询数据进行登录
if("sa".equals(name) && "123456".equals(pwd)) {
StpUtil.login(10001);
return SaResult.ok("登录成功!");
}
return SaResult.error("登录失败!");
})
;
}
}

View File

@@ -1,162 +0,0 @@
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=okfalse=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
+ "}";
}
}

View File

@@ -20,7 +20,7 @@ $('.login-btn').click(function(){
// 开始登录
setTimeout(function() {
$.ajax({
url: "doLogin",
url: "ssoDoLogin",
type: "post",
data: {
name: $('[name=name]').val(),

View File

@@ -1,15 +1,14 @@
package com.pj.sso;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import com.ejlchina.okhttps.OkHttps;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.sso.SaSsoUtil;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.sso.SaSsoHandle;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* Sa-Token-SSO Client端 Controller
@@ -28,44 +27,21 @@ public class SsoClientController {
return str;
}
// SSO-Client端登录地址
@RequestMapping("ssoLogin")
public Object ssoLogin(String back, String ticket) {
// 如果当前Client端已经登录则无需访问SSO认证中心可以直接返回
if(StpUtil.isLogin()) {
return new ModelAndView("redirect:" + back);
}
/*
* 接下来两种情况:
* ticket无值说明此请求是Client端访问需要重定向至SSO认证中心
* ticket有值说明此请求从SSO认证中心重定向而来需要根据ticket进行登录
*/
if(ticket == null) {
String serverAuthUrl = SaSsoUtil.buildServerAuthUrl(SaHolder.getRequest().getUrl(), back);
return new ModelAndView("redirect:" + serverAuthUrl);
} else {
Object loginId = checkTicket(ticket);
if(loginId != null ) {
// loginId有值说明ticket有效
StpUtil.login(loginId);
return new ModelAndView("redirect:" + back);
}
// 此处向客户端提示ticket无效即可不要重定向到SSO认证中心否则容易引起无限重定向
return "ticket无效: " + ticket;
}
// SSO-Client端处理所有SSO相关请求
@RequestMapping("/sso*")
public Object ssoRequest() {
return SaSsoHandle.clientRequest();
}
// SSO-Client端校验ticket码获取对应的账号id
private Object checkTicket(String ticket) {
// 构建单点注销的回调URL不需要单点注销时此值可填null
String sloCallback = SaHolder.getRequest().getUrl().replace("/ssoLogin", "/sloCallback");
// 使用OkHttps请求SSO-Server端校验ticket
String checkUrl = SaSsoUtil.buildCheckTicketUrl(ticket, sloCallback);
String loginId = OkHttps.sync(checkUrl).get().getBody().toString();
// 判断返回值是否为有效账号Id
return (SaFoxUtil.isEmpty(loginId) ? null : loginId);
// 配置SSO相关参数
@Autowired
private void configSso(SaTokenConfig cfg) {
cfg.sso
// 配置Http请求处理器
.setSendHttp(url -> {
return OkHttps.sync(url).get().getBody().toString();
})
;
}
}

View File

@@ -1,50 +0,0 @@
package com.pj.sso;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ejlchina.okhttps.OkHttps;
import com.pj.util.AjaxJson;
import cn.dev33.satoken.sso.SaSsoUtil;
import cn.dev33.satoken.stp.StpUtil;
/**
* Sa-Token-SSO Client端 单点注销 Controller
* @author kong
*/
@RestController
public class SsoClientLogoutController {
// SSO-Client端单端注销 (其它Client端会话不受影响)
@RequestMapping("logout")
public AjaxJson logout() {
StpUtil.logout();
return AjaxJson.getSuccess();
}
// SSO-Client端单点注销 (所有端一起下线)
@RequestMapping("ssoLogout")
public AjaxJson ssoLogout() {
// 如果未登录,则无需注销
if(StpUtil.isLogin() == false) {
return AjaxJson.getSuccess();
}
// 调用SSO-Server认证中心API
String url = SaSsoUtil.buildSloUrl(StpUtil.getLoginId());
String res = OkHttps.sync(url).get().getBody().toString();
if(res.equals("ok")) {
return AjaxJson.getSuccess("单点注销成功");
}
return AjaxJson.getError("单点注销失败");
}
// 单点注销的回调
@RequestMapping("sloCallback")
public String sloCallback(String loginId, String secretkey) {
SaSsoUtil.checkSecretkey(secretkey);
StpUtil.logoutByLoginId(loginId);
return "ok";
}
}

View File

@@ -1,162 +0,0 @@
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=okfalse=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
+ "}";
}
}

View File

@@ -14,11 +14,15 @@ sa-token:
sso:
# SSO-Server端 单点登录地址
auth-url: http://sa-sso-server.com:9000/ssoAuth
# 使用Http请求校验ticket
is-http: true
# SSO-Server端 ticket校验地址
check-ticket-url: http://sa-sso-server.com:9000/checkTicket
# SSO-Server端 单点注销地址
check-ticket-url: http://sa-sso-server.com:9000/ssoCheckTicket
# 打开单点注销功能
is-slo: true
# 单点注销地址
slo-url: http://sa-sso-server.com:9000/ssoLogout
# 接口调用秘钥用于SSO模式三的单点注销功能
# 接口调用秘钥
secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
spring:

View File

@@ -3,19 +3,19 @@ package com.pj.sso;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.pj.util.AjaxJson;
import cn.dev33.satoken.util.SaResult;
/**
* 全局异常处理
*/
@RestControllerAdvice
public class GlobalException {
public class ExceptionHandle {
// 全局异常拦截拦截项目中的所有异常
// 全局异常拦截
@ExceptionHandler
public AjaxJson handlerException(Exception e) {
public SaResult handlerException(Exception e) {
e.printStackTrace();
return AjaxJson.getError(e.getMessage());
return SaResult.error(e.getMessage());
}
}

View File

@@ -1,13 +1,16 @@
package com.pj.sso;
import org.springframework.beans.factory.annotation.Autowired;
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 com.ejlchina.okhttps.OkHttps;
import cn.dev33.satoken.sso.SaSsoUtil;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.sso.SaSsoHandle;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
/**
* Sa-Token-SSO Server端 Controller
@@ -17,45 +20,35 @@ import cn.dev33.satoken.stp.StpUtil;
@RestController
public class SsoServerController {
// SSO-Server端授权地址,跳转到登录页面
@RequestMapping("ssoAuth")
public Object ssoAuth(String redirect) {
/*
* 此处两种情况分开处理:
* 1、如果在SSO认证中心尚未登录则先去登登录
* 2、如果在SSO认证中心尚已登录则开始对redirect地址下放ticket引导授权
*/
// 情况1尚未登录
if(StpUtil.isLogin() == false) {
return new ModelAndView("sa-login.html");
}
// 情况2已经登录开始构建授权重定向地址下放ticket
String redirectUrl = SaSsoUtil.buildRedirectUrl(StpUtil.getLoginId(), redirect);
return new ModelAndView("redirect:" + redirectUrl);
// SSO-Server端处理所有SSO相关请求
@RequestMapping("/sso*")
public Object ssoRequest() {
return SaSsoHandle.serverRequest();
}
// 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("checkTicket")
public Object checkTicket(String ticket, String sloCallback) {
// 校验ticket获取对应的账号id
Object loginId = SaSsoUtil.checkTicket(ticket);
// 注册此客户端的单点注销回调URL不需要单点注销功能可删除此行代码
SaSsoUtil.registerSloCallbackUrl(loginId, sloCallback);
// 返回给Client端
return loginId;
// 配置SSO相关参数
@Autowired
private void configSso(SaTokenConfig cfg) {
cfg.sso
// SSO-Server端未登录时返回的View
.setNotLoginView(() -> {
return new ModelAndView("sa-login.html");
})
// SSO-Server端登录函数
.setDoLoginHandle((name, pwd) -> {
// 此处仅做模拟登录,真实环境应该查询数据进行登录
if("sa".equals(name) && "123456".equals(pwd)) {
StpUtil.login(10001);
return SaResult.ok("登录成功!");
}
return SaResult.error("登录失败!");
})
// 配置Http请求处理器
.setSendHttp(url -> {
// 此处为了提高响应速度这里可将sync换为async
return OkHttps.sync(url).get();
})
;
}
}

View File

@@ -1,28 +0,0 @@
package com.pj.sso;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ejlchina.okhttps.OkHttps;
import cn.dev33.satoken.sso.SaSsoUtil;
/**
* Sa-Token-SSO Server端 单点注销 Controller
* @author kong
*/
@RestController
public class SsoServerLogoutController {
// SSO-Server端单点注销
@RequestMapping("ssoLogout")
public String ssoLogout(String loginId, String secretkey) {
// 遍历通知Client端注销会话 (为了提高响应速度这里可将sync换为async)
SaSsoUtil.singleLogout(secretkey, loginId, url -> OkHttps.sync(url).get());
// 完成
return "ok";
}
}

View File

@@ -1,162 +0,0 @@
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=okfalse=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
+ "}";
}
}

View File

@@ -12,6 +12,10 @@ sa-token:
allow-url: http://sa-sso-client1.com:9001/ssoLogin, http://sa-sso-client2.com:9001/ssoLogin, http://sa-sso-client3.com:9001/ssoLogin
# 接口调用秘钥用于SSO模式三的单点注销功能
secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
# 使用Http请求校验ticket
is-http: true
# 打开单点注销功能
is-slo: true
spring:
# Redis配置

View File

@@ -20,7 +20,7 @@ $('.login-btn').click(function(){
// 开始登录
setTimeout(function() {
$.ajax({
url: "doLogin",
url: "ssoDoLogin",
type: "post",
data: {
name: $('[name=name]').val(),