mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-08-20 00:44:30 +08:00
feat(sso): 调整 SSO 示例适配最新版 & 新增 sso-resdk 示例 & 新增 sso-anon 示例
This commit is contained in:
parent
213d98d848
commit
2ecd52b3be
@ -149,8 +149,10 @@ public class SaResult extends LinkedHashMap<String, Object> implements Serializa
|
|||||||
* @return 对象自身
|
* @return 对象自身
|
||||||
*/
|
*/
|
||||||
public SaResult setMap(Map<String, ?> map) {
|
public SaResult setMap(Map<String, ?> map) {
|
||||||
for (String key : map.keySet()) {
|
if(map != null) {
|
||||||
this.put(key, map.get(key));
|
for (String key : map.keySet()) {
|
||||||
|
this.put(key, map.get(key));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,8 +44,9 @@
|
|||||||
<module>sa-token-demo-sso/sa-token-demo-sso1-client</module>
|
<module>sa-token-demo-sso/sa-token-demo-sso1-client</module>
|
||||||
<module>sa-token-demo-sso/sa-token-demo-sso2-client</module>
|
<module>sa-token-demo-sso/sa-token-demo-sso2-client</module>
|
||||||
<module>sa-token-demo-sso/sa-token-demo-sso3-client</module>
|
<module>sa-token-demo-sso/sa-token-demo-sso3-client</module>
|
||||||
<module>sa-token-demo-sso/sa-token-demo-sso3-client-test2</module>
|
|
||||||
<module>sa-token-demo-sso/sa-token-demo-sso3-client-nosdk</module>
|
<module>sa-token-demo-sso/sa-token-demo-sso3-client-nosdk</module>
|
||||||
|
<module>sa-token-demo-sso/sa-token-demo-sso3-client-resdk</module>
|
||||||
|
<module>sa-token-demo-sso/sa-token-demo-sso3-client-anon</module>
|
||||||
<module>sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon</module>
|
<module>sa-token-demo-sso-for-solon/sa-token-demo-sso-server-solon</module>
|
||||||
<module>sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon</module>
|
<module>sa-token-demo-sso-for-solon/sa-token-demo-sso1-client-solon</module>
|
||||||
<module>sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon</module>
|
<module>sa-token-demo-sso-for-solon/sa-token-demo-sso2-client-solon</module>
|
||||||
|
|||||||
@ -8,22 +8,59 @@
|
|||||||
<h2>Sa-Token SSO-Client 应用端(前后端分离版-原生h5)</h2>
|
<h2>Sa-Token SSO-Client 应用端(前后端分离版-原生h5)</h2>
|
||||||
<p>当前是否登录:<b class="is-login"></b></p>
|
<p>当前是否登录:<b class="is-login"></b></p>
|
||||||
<p>
|
<p>
|
||||||
<a class="login-btn">登录</a>
|
<a href="javascript: login();">登录</a> -
|
||||||
<a class="logout-btn">注销</a>
|
<a href="javascript: doLogoutByAlone();">单应用注销</a> -
|
||||||
|
<a href="javascript: doLogoutBySingleDeviceId();">单浏览器注销</a> -
|
||||||
|
<a href="javascript: doLogout();">全端注销</a> -
|
||||||
|
<a href="javascript: doMyInfo();">账号资料</a>
|
||||||
</p>
|
</p>
|
||||||
<script src="common.js"></script>
|
<script src="sso-common.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
document.querySelector('.login-btn').href = 'sso-login.html?back=' + encodeURIComponent(location.href);
|
// 登录
|
||||||
document.querySelector('.logout-btn').href = baseUrl + '/sso/logout?satoken=' + localStorage.satoken + '&back=' + encodeURIComponent(location.href);
|
function login() {
|
||||||
|
location.href = 'sso-login.html?back=' + encodeURIComponent(location.href);
|
||||||
|
}
|
||||||
|
|
||||||
ajax('/sso/isLogin', {}, function(res){
|
// 单应用注销
|
||||||
if(res.data) {
|
function doLogoutByAlone() {
|
||||||
setHtml('.is-login', res.data + ' (' + res.loginId + ')');
|
ajax('/sso/logoutByAlone', {}, function(res){
|
||||||
} else {
|
doIsLogin();
|
||||||
setHtml('.is-login', res.data);
|
})
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
// 单浏览器注销
|
||||||
|
function doLogoutBySingleDeviceId() {
|
||||||
|
ajax('/sso/logout', { singleDeviceIdLogout: true }, function(res){
|
||||||
|
doIsLogin();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全端注销
|
||||||
|
function doLogout() {
|
||||||
|
ajax('/sso/logout', { }, function(res){
|
||||||
|
doIsLogin();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 账号资料
|
||||||
|
function doMyInfo() {
|
||||||
|
ajax('/sso/myInfo', { }, function(res){
|
||||||
|
alert(JSON.stringify(res));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否登录
|
||||||
|
function doIsLogin() {
|
||||||
|
ajax('/sso/isLogin', {}, function(res){
|
||||||
|
if(res.data) {
|
||||||
|
setHtml('.is-login', res.data + ' (' + res.loginId + ')');
|
||||||
|
} else {
|
||||||
|
setHtml('.is-login', res.data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
doIsLogin();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
// 服务器接口主机地址
|
// 服务器接口主机地址
|
||||||
var baseUrl = "http://sa-sso-client1.com:9003";
|
// var baseUrl = "http://sa-sso-client1.com:9002"; // 模式二后端
|
||||||
|
var baseUrl = "http://sa-sso-client1.com:9003"; // 模式三后端
|
||||||
|
|
||||||
// 封装一下Ajax
|
// 封装一下Ajax
|
||||||
function ajax(path, data, successFn, errorFn) {
|
function ajax(path, data, successFn, errorFn) {
|
||||||
@ -2,16 +2,16 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Sa-Token-SSO-Client端-登录页</title>
|
<title>Sa-Token-SSO-Client端-登录中转页页</title>
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="login-box">
|
<div class="login-box">
|
||||||
|
加载中 ...
|
||||||
</div>
|
</div>
|
||||||
<script src="common.js"></script>
|
<script src="sso-common.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
var back = getParam('back', '/');
|
var back = getParam('back', '/');
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
// sso-client 的后端服务地址
|
// sso-client 的后端服务地址
|
||||||
export const baseUrl = "http://sa-sso-client1.com:9001";
|
// export const baseUrl = "http://sa-sso-client1.com:9002"; // 模式二后端
|
||||||
|
export const baseUrl = "http://sa-sso-client1.com:9003"; // 模式三后端
|
||||||
|
|
||||||
// 封装一下 Ajax 方法
|
// 封装一下 Ajax 方法
|
||||||
export const ajax = function(path, data, successFn) {
|
export const ajax = function(path, data, successFn) {
|
||||||
|
console.log('发起请求:', baseUrl + path, JSON.stringify(data));
|
||||||
axios({
|
axios({
|
||||||
url: baseUrl + path,
|
url: baseUrl + path,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
@ -16,9 +18,14 @@ export const ajax = function(path, data, successFn) {
|
|||||||
}).
|
}).
|
||||||
then(function (response) { // 成功时执行
|
then(function (response) { // 成功时执行
|
||||||
const res = response.data;
|
const res = response.data;
|
||||||
|
console.log('返回数据:', res);
|
||||||
|
if(res.code === 500) {
|
||||||
|
return alert(res.msg);
|
||||||
|
}
|
||||||
successFn(res);
|
successFn(res);
|
||||||
}).
|
}).
|
||||||
catch(function (error) {
|
catch(function (error) {
|
||||||
|
console.error('请求失败:', error);
|
||||||
return alert("异常:" + JSON.stringify(error));
|
return alert("异常:" + JSON.stringify(error));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -2,35 +2,76 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h2> Sa-Token SSO-Client 应用端(前后端分离版-Vue2) </h2>
|
<h2> Sa-Token SSO-Client 应用端(前后端分离版-Vue2) </h2>
|
||||||
<p>当前是否登录:<b>{{isLogin}}</b></p>
|
<p>当前是否登录:<b>{{isLogin}} ({{ loginId }})</b></p>
|
||||||
<p>
|
<p>
|
||||||
<router-link :to="loginUrl">登录</router-link>
|
<a href="javascript: null;" @click="login()" >登录</a> -
|
||||||
<a :href="logoutUrl">注销</a>
|
<a href="javascript: null;" @click="doLogoutByAlone()" >单应用注销</a> -
|
||||||
|
<a href="javascript: null;" @click="doLogoutBySingleDeviceId();">单浏览器注销</a> -
|
||||||
|
<a href="javascript: null;" @click="doLogout();">全端注销</a> -
|
||||||
|
<a href="javascript: null;" @click="doMyInfo();">账号资料</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {baseUrl, ajax} from './method-util.js'
|
import {ajax} from './sso-common.js'
|
||||||
|
import router from "@/router";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// 单点登录地址
|
|
||||||
loginUrl: '/sso-login?back=' + encodeURIComponent(location.href),
|
|
||||||
// 单点注销地址
|
|
||||||
logoutUrl: baseUrl + '/sso/logout?satoken=' + localStorage.satoken + '&back=' + encodeURIComponent(location.href),
|
|
||||||
// 是否登录
|
// 是否登录
|
||||||
isLogin: false
|
isLogin: false,
|
||||||
|
// 登录账号
|
||||||
|
loginId: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
// 登录
|
||||||
|
login: function() {
|
||||||
|
router.push('/sso-login?back=' + encodeURIComponent(location.href));
|
||||||
|
},
|
||||||
|
|
||||||
|
// 单应用注销
|
||||||
|
doLogoutByAlone: function() {
|
||||||
|
ajax('/sso/logoutByAlone', {}, function(){
|
||||||
|
this.doIsLogin();
|
||||||
|
}.bind(this))
|
||||||
|
},
|
||||||
|
|
||||||
|
// 单浏览器注销
|
||||||
|
doLogoutBySingleDeviceId: function() {
|
||||||
|
ajax('/sso/logout', { singleDeviceIdLogout: true }, function(){
|
||||||
|
this.doIsLogin();
|
||||||
|
}.bind(this))
|
||||||
|
},
|
||||||
|
|
||||||
|
// 全端注销
|
||||||
|
doLogout: function () {
|
||||||
|
ajax('/sso/logout', { }, function(){
|
||||||
|
this.doIsLogin();
|
||||||
|
}.bind(this))
|
||||||
|
},
|
||||||
|
|
||||||
|
// 账号资料
|
||||||
|
doMyInfo: function() {
|
||||||
|
ajax('/sso/myInfo', { }, function(res){
|
||||||
|
alert(JSON.stringify(res));
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 判断是否登录
|
||||||
|
doIsLogin: function() {
|
||||||
|
ajax('/sso/isLogin', {}, function(res){
|
||||||
|
this.isLogin = res.data;
|
||||||
|
this.loginId = res.loginId;
|
||||||
|
}.bind(this))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
// 查询当前会话是否登录
|
this.doIsLogin();
|
||||||
ajax('/sso/isLogin', {}, function (res) {
|
|
||||||
console.log('/isLogin 返回数据:', res);
|
|
||||||
this.isLogin = res.data;
|
|
||||||
}.bind(this))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
<!-- Sa-Token-SSO-Client端-登录页 -->
|
<!-- Sa-Token-SSO-Client端-登录中转页 -->
|
||||||
<template>
|
<template>
|
||||||
<div></div>
|
<div>加载中...</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {ajax, getParam} from './method-util.js';
|
import {ajax, getParam} from './sso-common.js';
|
||||||
import router from '../router';
|
import router from '../router';
|
||||||
|
|
||||||
|
|
||||||
@ -31,14 +31,12 @@ export default {
|
|||||||
// 重定向至认证中心
|
// 重定向至认证中心
|
||||||
goSsoAuthUrl: function() {
|
goSsoAuthUrl: function() {
|
||||||
ajax('/sso/getSsoAuthUrl', {clientLoginUrl: location.href}, function(res) {
|
ajax('/sso/getSsoAuthUrl', {clientLoginUrl: location.href}, function(res) {
|
||||||
console.log('/sso/getSsoAuthUrl 返回数据', res);
|
|
||||||
location.href = res.data;
|
location.href = res.data;
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
// 根据ticket值登录
|
// 根据ticket值登录
|
||||||
doLoginByTicket: function(ticket) {
|
doLoginByTicket: function(ticket) {
|
||||||
ajax('/sso/doLoginByTicket', {ticket: ticket}, function(res) {
|
ajax('/sso/doLoginByTicket', {ticket: ticket}, function(res) {
|
||||||
console.log('/sso/doLoginByTicket 返回数据', res);
|
|
||||||
if(res.code === 200) {
|
if(res.code === 200) {
|
||||||
localStorage.setItem('satoken', res.data);
|
localStorage.setItem('satoken', res.data);
|
||||||
location.href = decodeURIComponent(this.back);
|
location.href = decodeURIComponent(this.back);
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import { createRouter, createWebHashHistory } from 'vue-router';
|
import { createRouter, createWebHistory } from 'vue-router';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建 vue-router 实例
|
* 创建 vue-router 实例
|
||||||
*/
|
*/
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHashHistory(),
|
history: createWebHistory(),
|
||||||
routes: [
|
routes: [
|
||||||
// 首页
|
// 首页
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
// sso-client 的后端服务地址
|
// sso-client 的后端服务地址
|
||||||
export const baseUrl = "http://sa-sso-client1.com:9001";
|
// export const baseUrl = "http://sa-sso-client1.com:9002"; // 模式二后端
|
||||||
|
export const baseUrl = "http://sa-sso-client1.com:9003"; // 模式三后端
|
||||||
|
|
||||||
// 封装一下 Ajax 方法
|
// 封装一下 Ajax 方法
|
||||||
export const ajax = function(path, data, successFn) {
|
export const ajax = function(path, data, successFn) {
|
||||||
|
console.log('发起请求:', baseUrl + path, JSON.stringify(data));
|
||||||
axios({
|
axios({
|
||||||
url: baseUrl + path,
|
url: baseUrl + path,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
@ -16,9 +18,14 @@ export const ajax = function(path, data, successFn) {
|
|||||||
}).
|
}).
|
||||||
then(function (response) { // 成功时执行
|
then(function (response) { // 成功时执行
|
||||||
const res = response.data;
|
const res = response.data;
|
||||||
|
console.log('返回数据:', res);
|
||||||
|
if(res.code === 500) {
|
||||||
|
return alert(res.msg);
|
||||||
|
}
|
||||||
successFn(res);
|
successFn(res);
|
||||||
}).
|
}).
|
||||||
catch(function (error) {
|
catch(function (error) {
|
||||||
|
console.error('请求失败:', error);
|
||||||
return alert("异常:" + JSON.stringify(error));
|
return alert("异常:" + JSON.stringify(error));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1,29 +1,70 @@
|
|||||||
<!-- 项目首页 -->
|
<!-- 项目首页 -->
|
||||||
<template>
|
<template>
|
||||||
<h2> Sa-Token SSO-Client 应用端(前后端分离版-Vue3) </h2>
|
<div>
|
||||||
<p>当前是否登录:<b>{{isLogin}}</b></p>
|
<h2> Sa-Token SSO-Client 应用端(前后端分离版-Vue3) </h2>
|
||||||
<p>
|
<p>当前是否登录:<b>{{ state.isLogin }} ({{ state.loginId }})</b></p>
|
||||||
<router-link :to="loginUrl">登录</router-link>
|
<p>
|
||||||
<a :href="logoutUrl">注销</a>
|
<a href="javascript: null;" @click="login()" >登录</a> -
|
||||||
</p>
|
<a href="javascript: null;" @click="doLogoutByAlone()" >单应用注销</a> -
|
||||||
|
<a href="javascript: null;" @click="doLogoutBySingleDeviceId();">单浏览器注销</a> -
|
||||||
|
<a href="javascript: null;" @click="doLogout();">全端注销</a> -
|
||||||
|
<a href="javascript: null;" @click="doMyInfo();">账号资料</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { reactive } from 'vue'
|
||||||
import {baseUrl, ajax} from './method-util.js'
|
import { ajax } from './sso-common.js'
|
||||||
|
import router from "../router/index.js";
|
||||||
|
|
||||||
// 单点登录地址
|
// 数据
|
||||||
const loginUrl = '/sso-login?back=' + encodeURIComponent(location.href);
|
const state = reactive({
|
||||||
// 单点注销地址
|
isLogin: false,
|
||||||
const logoutUrl = baseUrl + '/sso/logout?satoken=' + localStorage.satoken + '&back=' + encodeURIComponent(location.href);
|
loginId: '',
|
||||||
|
|
||||||
// 是否登录
|
|
||||||
const isLogin = ref(false);
|
|
||||||
|
|
||||||
// 查询当前会话是否登录
|
|
||||||
ajax('/sso/isLogin', {}, function (res) {
|
|
||||||
console.log('/isLogin 返回数据:', res);
|
|
||||||
isLogin.value = res.data;
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 登录
|
||||||
|
function login() {
|
||||||
|
router.push('/sso-login?back=' + encodeURIComponent(location.href));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单应用注销
|
||||||
|
function doLogoutByAlone() {
|
||||||
|
ajax('/sso/logoutByAlone', {}, function(res){
|
||||||
|
doIsLogin();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单浏览器注销
|
||||||
|
function doLogoutBySingleDeviceId() {
|
||||||
|
ajax('/sso/logout', { singleDeviceIdLogout: true }, function(res){
|
||||||
|
doIsLogin();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全端注销
|
||||||
|
function doLogout() {
|
||||||
|
ajax('/sso/logout', { }, function(res){
|
||||||
|
doIsLogin();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 账号资料
|
||||||
|
function doMyInfo() {
|
||||||
|
ajax('/sso/myInfo', { }, function(res){
|
||||||
|
alert(JSON.stringify(res));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否登录
|
||||||
|
function doIsLogin() {
|
||||||
|
ajax('/sso/isLogin', {}, function(res){
|
||||||
|
state.isLogin = res.data;
|
||||||
|
state.loginId = res.loginId;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
doIsLogin();
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
<!-- Sa-Token-SSO-Client端-登录页 -->
|
<!-- Sa-Token-SSO-Client端-登录页 -->
|
||||||
<template>
|
<template>
|
||||||
|
<div>加载中...</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {onMounted} from "vue";
|
import {onMounted} from "vue";
|
||||||
import {ajax, getParam} from './method-util.js';
|
import {ajax, getParam} from './sso-common.js';
|
||||||
import router from '../router';
|
import router from '../router';
|
||||||
|
|
||||||
// 获取参数
|
// 获取参数
|
||||||
@ -27,7 +27,6 @@ onMounted(() => {
|
|||||||
// 重定向至认证中心
|
// 重定向至认证中心
|
||||||
function goSsoAuthUrl() {
|
function goSsoAuthUrl() {
|
||||||
ajax('/sso/getSsoAuthUrl', {clientLoginUrl: location.href}, function(res) {
|
ajax('/sso/getSsoAuthUrl', {clientLoginUrl: location.href}, function(res) {
|
||||||
console.log('/sso/getSsoAuthUrl 返回数据', res);
|
|
||||||
location.href = res.data;
|
location.href = res.data;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -35,7 +34,6 @@ function goSsoAuthUrl() {
|
|||||||
// 根据ticket值登录
|
// 根据ticket值登录
|
||||||
function doLoginByTicket(ticket) {
|
function doLoginByTicket(ticket) {
|
||||||
ajax('/sso/doLoginByTicket', {ticket: ticket}, function(res) {
|
ajax('/sso/doLoginByTicket', {ticket: ticket}, function(res) {
|
||||||
console.log('/sso/doLoginByTicket 返回数据', res);
|
|
||||||
if(res.code === 200) {
|
if(res.code === 200) {
|
||||||
localStorage.setItem('satoken', res.data);
|
localStorage.setItem('satoken', res.data);
|
||||||
location.href = decodeURIComponent(back);
|
location.href = decodeURIComponent(back);
|
||||||
|
|||||||
@ -14,7 +14,7 @@ public class SaSsoServerApplication {
|
|||||||
System.out.println("---------------------- Sa-Token SSO 统一认证中心启动成功 ----------------------");
|
System.out.println("---------------------- Sa-Token SSO 统一认证中心启动成功 ----------------------");
|
||||||
System.out.println("配置信息:" + SaSsoManager.getServerConfig());
|
System.out.println("配置信息:" + SaSsoManager.getServerConfig());
|
||||||
System.out.println("统一认证登录地址:http://sa-sso-server.com:9000/sso/auth");
|
System.out.println("统一认证登录地址:http://sa-sso-server.com:9000/sso/auth");
|
||||||
System.out.println("测试前需要根据官网文档修改hosts文件,测试账号密码:sa / 123456");
|
System.out.println("测试前需要根据官网文档修改 hosts 文件,测试账号密码:sa / 123456");
|
||||||
System.out.println();
|
System.out.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
package com.pj.home;
|
package com.pj.sso;
|
||||||
|
|
||||||
import cn.dev33.satoken.context.SaHolder;
|
import cn.dev33.satoken.context.SaHolder;
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
@ -1,7 +1,6 @@
|
|||||||
package com.pj.sso;
|
package com.pj.sso;
|
||||||
|
|
||||||
import cn.dev33.satoken.context.SaHolder;
|
import cn.dev33.satoken.context.SaHolder;
|
||||||
import cn.dev33.satoken.sign.SaSignUtil;
|
|
||||||
import cn.dev33.satoken.sso.processor.SaSsoServerProcessor;
|
import cn.dev33.satoken.sso.processor.SaSsoServerProcessor;
|
||||||
import cn.dev33.satoken.sso.template.SaSsoServerTemplate;
|
import cn.dev33.satoken.sso.template.SaSsoServerTemplate;
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
@ -23,10 +22,9 @@ public class SsoServerController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* SSO-Server端:处理所有SSO相关请求
|
* SSO-Server端:处理所有SSO相关请求
|
||||||
* http://{host}:{port}/sso/auth -- 单点登录授权地址,接受参数:redirect=授权重定向地址
|
* http://{host}:{port}/sso/auth -- 单点登录授权地址
|
||||||
* http://{host}:{port}/sso/doLogin -- 账号密码登录接口,接受参数:name、pwd
|
* http://{host}:{port}/sso/doLogin -- 账号密码登录接口,接受参数:name、pwd
|
||||||
* http://{host}:{port}/sso/checkTicket -- Ticket校验接口(isHttp=true时打开),接受参数:ticket=ticket码、ssoLogoutCall=单点注销回调地址 [可选]
|
* http://{host}:{port}/sso/signout -- 单点注销地址(isSlo=true时打开)
|
||||||
* http://{host}:{port}/sso/signout -- 单点注销地址(isSlo=true时打开),接受参数:loginId=账号id、sign=参数签名
|
|
||||||
*/
|
*/
|
||||||
@RequestMapping("/sso/*")
|
@RequestMapping("/sso/*")
|
||||||
public Object ssoRequest() {
|
public Object ssoRequest() {
|
||||||
@ -53,24 +51,19 @@ public class SsoServerController {
|
|||||||
return SaResult.error("登录失败!");
|
return SaResult.error("登录失败!");
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
// 添加消息处理器:userinfo (获取用户资料) (用于在模式三下,为 client 端开放拉取数据的接口)
|
||||||
|
ssoServerTemplate.messageHolder.addHandle("userinfo", (ssoTemplate, message) -> {
|
||||||
|
System.out.println("收到消息:" + message);
|
||||||
|
System.out.println("loginId=" + message.get("loginId"));
|
||||||
|
|
||||||
// 示例:获取数据接口(用于在模式三下,为 client 端开放拉取数据的接口)
|
// 自定义返回结果(模拟)
|
||||||
@RequestMapping("/sso/getData")
|
return SaResult.ok()
|
||||||
public SaResult getData(String apiType, String loginId) {
|
.set("id", message.get("loginId"))
|
||||||
System.out.println("---------------- 获取数据 ----------------");
|
.set("name", "LinXiaoYu")
|
||||||
System.out.println("apiType=" + apiType);
|
.set("sex", "女")
|
||||||
System.out.println("loginId=" + loginId);
|
.set("age", 18);
|
||||||
|
});
|
||||||
|
|
||||||
// 校验签名:只有拥有正确秘钥发起的请求才能通过校验
|
|
||||||
SaSignUtil.checkRequest(SaHolder.getRequest());
|
|
||||||
|
|
||||||
// 自定义返回结果(模拟)
|
|
||||||
return SaResult.ok()
|
|
||||||
.set("id", loginId)
|
|
||||||
.set("name", "LinXiaoYu")
|
|
||||||
.set("sex", "女")
|
|
||||||
.set("age", 18);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,43 +7,57 @@ sa-token:
|
|||||||
# 打印操作日志
|
# 打印操作日志
|
||||||
is-log: true
|
is-log: true
|
||||||
|
|
||||||
# ------- SSO-模式一相关配置 (非模式一不需要配置)
|
# ------- SSO 模式一配置 (非模式一不需要配置)
|
||||||
# cookie:
|
# cookie:
|
||||||
# 配置 Cookie 作用域
|
# # 配置 Cookie 作用域
|
||||||
# domain: stp.com
|
# domain: stp.com
|
||||||
|
|
||||||
# ------- SSO-模式二相关配置
|
# SSO-Server 配置
|
||||||
sso-server:
|
sso-server:
|
||||||
# Ticket有效期 (单位: 秒),默认五分钟
|
# Ticket有效期 (单位: 秒),默认五分钟
|
||||||
ticket-timeout: 300
|
ticket-timeout: 300
|
||||||
# 所有允许的授权回调地址
|
# 主页路由,在不指定 redirect 参数时,默认跳转的地址
|
||||||
|
home-route: /home
|
||||||
|
# 是否启用匿名 client (开启匿名 client 后,允许客户端接入时不提交 client 参数)
|
||||||
|
allow-anon-client: true
|
||||||
|
# 所有允许的授权回调地址 (匿名 client 使用)
|
||||||
allow-url: "*"
|
allow-url: "*"
|
||||||
# API 接口调用秘钥 (默认)
|
# API 接口调用秘钥 (全局默认 + 匿名 client 使用)
|
||||||
secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||||
# 是否启用匿名 client
|
# 应用列表:配置接入的应用信息
|
||||||
allow-anon-client: false
|
|
||||||
|
|
||||||
# ------- SSO-模式三相关配置 (下面的配置在使用SSO模式三时打开)
|
|
||||||
# 是否打开模式三
|
|
||||||
is-http: true
|
|
||||||
|
|
||||||
clients:
|
clients:
|
||||||
# 应用 sso-client2,采用模式二对接 (跨域、同Redis)
|
# 应用 sso-client2:采用模式二对接 (跨域、同Redis)
|
||||||
sso-client2:
|
sso-client2:
|
||||||
client: sso-client2
|
client: sso-client2
|
||||||
allow-url: "*"
|
allow-url: "*"
|
||||||
# 应用 sso-client3,采用模式三对接 (跨域、跨Redis)
|
secret-key: SSO-C2-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||||
|
# 应用 sso-client3:采用模式三对接 (跨域、跨Redis)
|
||||||
sso-client3:
|
sso-client3:
|
||||||
|
# 应用名称
|
||||||
client: sso-client3
|
client: sso-client3
|
||||||
|
# 允许授权地址
|
||||||
allow-url: "*"
|
allow-url: "*"
|
||||||
secret-key: SSO-C3-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
# 是否接收消息推送
|
||||||
|
is-push: true
|
||||||
|
# 消息推送地址
|
||||||
push-url: http://sa-sso-client1.com:9003/sso/pushC
|
push-url: http://sa-sso-client1.com:9003/sso/pushC
|
||||||
|
# 接口调用秘钥 (如果不配置则使用全局默认秘钥)
|
||||||
|
secret-key: SSO-C3-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||||
# ---- 除了以上配置项,你还需要为 Sa-Token 配置http请求处理器(文档有步骤说明)
|
# 应用 sso-client3-resdk:采用 ReSdk 模式对接
|
||||||
|
sso-client3-resdk:
|
||||||
|
# 应用名称
|
||||||
|
client: sso-client3-resdk
|
||||||
|
# 允许授权地址
|
||||||
|
allow-url: "*"
|
||||||
|
# 是否接收消息推送
|
||||||
|
is-push: true
|
||||||
|
# 消息推送地址
|
||||||
|
push-url: http://sa-sso-client1.com:9005/sso/pushC
|
||||||
|
# 接口调用秘钥 (如果不配置则使用全局默认秘钥)
|
||||||
|
secret-key: SSO-C3-ReSdk-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
# Redis配置 (SSO模式一和模式二使用Redis来同步会话)
|
# Redis配置 (SSO模式一和模式二使用 Redis 来同步会话)
|
||||||
redis:
|
redis:
|
||||||
# Redis数据库索引(默认为0)
|
# Redis数据库索引(默认为0)
|
||||||
database: 1
|
database: 1
|
||||||
|
|||||||
@ -21,7 +21,7 @@ public class SaSso1ClientApplication {
|
|||||||
System.out.println("测试访问应用端一: http://s1.stp.com:9001");
|
System.out.println("测试访问应用端一: http://s1.stp.com:9001");
|
||||||
System.out.println("测试访问应用端二: http://s2.stp.com:9001");
|
System.out.println("测试访问应用端二: http://s2.stp.com:9001");
|
||||||
System.out.println("测试访问应用端三: http://s3.stp.com:9001");
|
System.out.println("测试访问应用端三: http://s3.stp.com:9001");
|
||||||
System.out.println("测试前需要根据官网文档修改hosts文件,测试账号密码:sa / 123456");
|
System.out.println("测试前需要根据官网文档修改 hosts 文件,测试账号密码:sa / 123456");
|
||||||
System.out.println();
|
System.out.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,11 +18,11 @@ public class SsoClientController {
|
|||||||
@RequestMapping("/")
|
@RequestMapping("/")
|
||||||
public String index() {
|
public String index() {
|
||||||
String authUrl = SaSsoManager.getClientConfig().splicingAuthUrl();
|
String authUrl = SaSsoManager.getClientConfig().splicingAuthUrl();
|
||||||
String solUrl = SaSsoManager.getClientConfig().splicingSignoutUrl();
|
String signoutUrl = SaSsoManager.getClientConfig().splicingSignoutUrl();
|
||||||
String str = "<h2>Sa-Token SSO-Client 应用端</h2>" +
|
String str = "<h2>Sa-Token SSO-Client 应用端 (模式一)</h2>" +
|
||||||
"<p>当前会话是否登录:" + StpUtil.isLogin() + "</p>" +
|
"<p>当前会话是否登录:" + StpUtil.isLogin() + " (" + StpUtil.getLoginId("") + ")</p>" +
|
||||||
"<p><a href=\"javascript:location.href='" + authUrl + "?mode=simple&redirect=' + encodeURIComponent(location.href);\">登录</a> " +
|
"<p><a href=\"javascript:location.href='" + authUrl + "?mode=simple&redirect=' + encodeURIComponent(location.href);\">登录</a> " +
|
||||||
"<a href=\"javascript:location.href='" + solUrl + "?back=' + encodeURIComponent(location.href);\">注销</a> </p>";
|
"<a href=\"javascript:location.href='" + signoutUrl + "?back=' + encodeURIComponent(location.href);\">注销</a> </p>";
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ sa-token:
|
|||||||
# SSO-Server端主机地址
|
# SSO-Server端主机地址
|
||||||
server-url: http://sso.stp.com:9000
|
server-url: http://sso.stp.com:9000
|
||||||
|
|
||||||
# 配置 Sa-Token 单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis)
|
# 配置 Sa-Token 单独使用的Redis连接 (需要引入 sa-token-alone-redis 依赖) (此处需要和 SSO-Server 端连接同一个Redis)
|
||||||
alone-redis:
|
alone-redis:
|
||||||
# Redis数据库索引
|
# Redis数据库索引
|
||||||
database: 1
|
database: 1
|
||||||
|
|||||||
@ -61,11 +61,11 @@
|
|||||||
<version>${sa-token.version}</version>
|
<version>${sa-token.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Http请求工具 -->
|
<!-- Sa-Token 插件:整合 Forest 请求工具 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.dtflys.forest</groupId>
|
<groupId>cn.dev33</groupId>
|
||||||
<artifactId>forest-spring-boot-starter</artifactId>
|
<artifactId>sa-token-forest</artifactId>
|
||||||
<version>1.5.26</version>
|
<version>${sa-token.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@ -16,7 +16,7 @@ public class SaSso2ClientApplication {
|
|||||||
System.out.println("测试访问应用端一: http://sa-sso-client1.com:9002");
|
System.out.println("测试访问应用端一: http://sa-sso-client1.com:9002");
|
||||||
System.out.println("测试访问应用端二: http://sa-sso-client2.com:9002");
|
System.out.println("测试访问应用端二: http://sa-sso-client2.com:9002");
|
||||||
System.out.println("测试访问应用端三: http://sa-sso-client3.com:9002");
|
System.out.println("测试访问应用端三: http://sa-sso-client3.com:9002");
|
||||||
System.out.println("测试前需要根据官网文档修改hosts文件,测试账号密码:sa / 123456");
|
System.out.println("测试前需要根据官网文档修改 hosts 文件,测试账号密码:sa / 123456");
|
||||||
System.out.println();
|
System.out.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,11 +2,10 @@ package com.pj.h5;
|
|||||||
|
|
||||||
import cn.dev33.satoken.sso.model.SaCheckTicketResult;
|
import cn.dev33.satoken.sso.model.SaCheckTicketResult;
|
||||||
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
|
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
|
||||||
import cn.dev33.satoken.sso.template.SaSsoUtil;
|
import cn.dev33.satoken.sso.template.SaSsoClientUtil;
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
||||||
import cn.dev33.satoken.util.SaResult;
|
import cn.dev33.satoken.util.SaResult;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@ -28,14 +27,14 @@ public class H5Controller {
|
|||||||
// 返回SSO认证中心登录地址
|
// 返回SSO认证中心登录地址
|
||||||
@RequestMapping("/sso/getSsoAuthUrl")
|
@RequestMapping("/sso/getSsoAuthUrl")
|
||||||
public SaResult getSsoAuthUrl(String clientLoginUrl) {
|
public SaResult getSsoAuthUrl(String clientLoginUrl) {
|
||||||
String serverAuthUrl = SaSsoUtil.buildServerAuthUrl(clientLoginUrl, "");
|
String serverAuthUrl = SaSsoClientUtil.buildServerAuthUrl(clientLoginUrl, "");
|
||||||
return SaResult.data(serverAuthUrl);
|
return SaResult.data(serverAuthUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据ticket进行登录
|
// 根据ticket进行登录
|
||||||
@RequestMapping("/sso/doLoginByTicket")
|
@RequestMapping("/sso/doLoginByTicket")
|
||||||
public SaResult doLoginByTicket(String ticket) {
|
public SaResult doLoginByTicket(String ticket) {
|
||||||
SaCheckTicketResult ctr = SaSsoClientProcessor.instance.checkTicket(ticket, "/sso/doLoginByTicket");
|
SaCheckTicketResult ctr = SaSsoClientProcessor.instance.checkTicket(ticket);
|
||||||
StpUtil.login(ctr.loginId, new SaLoginParameter()
|
StpUtil.login(ctr.loginId, new SaLoginParameter()
|
||||||
.setTimeout(ctr.remainTokenTimeout)
|
.setTimeout(ctr.remainTokenTimeout)
|
||||||
.setDeviceId(ctr.deviceId)
|
.setDeviceId(ctr.deviceId)
|
||||||
@ -43,11 +42,4 @@ public class H5Controller {
|
|||||||
return SaResult.data(StpUtil.getTokenValue());
|
return SaResult.data(StpUtil.getTokenValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 全局异常拦截
|
|
||||||
@ExceptionHandler
|
|
||||||
public SaResult handlerException(Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return SaResult.error(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Sa-Token 权限认证] 配置类 (解决跨域问题)
|
* [Sa-Token 权限认证] 配置类
|
||||||
*
|
*
|
||||||
* @author click33
|
* @author click33
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.pj.sso;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.util.SaResult;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局异常处理
|
||||||
|
* @author click33
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@RestControllerAdvice
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
// 全局异常拦截
|
||||||
|
@ExceptionHandler
|
||||||
|
public SaResult handlerException(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return SaResult.error(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,12 +1,13 @@
|
|||||||
package com.pj.sso;
|
package com.pj.sso;
|
||||||
|
|
||||||
import cn.dev33.satoken.sso.SaSsoManager;
|
import cn.dev33.satoken.context.SaHolder;
|
||||||
|
import cn.dev33.satoken.sso.message.SaSsoMessage;
|
||||||
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
|
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
|
||||||
import cn.dev33.satoken.sso.template.SaSsoClientTemplate;
|
import cn.dev33.satoken.sso.template.SaSsoClientTemplate;
|
||||||
|
import cn.dev33.satoken.sso.template.SaSsoClientUtil;
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import cn.dev33.satoken.util.SaResult;
|
import cn.dev33.satoken.util.SaResult;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@ -20,19 +21,23 @@ public class SsoClientController {
|
|||||||
// 首页
|
// 首页
|
||||||
@RequestMapping("/")
|
@RequestMapping("/")
|
||||||
public String index() {
|
public String index() {
|
||||||
String solUrl = SaSsoManager.getClientConfig().splicingSignoutUrl();
|
String str = "<h2>Sa-Token SSO-Client 应用端 (模式二)</h2>" +
|
||||||
String str = "<h2>Sa-Token SSO-Client 应用端</h2>" +
|
"<p>当前会话是否登录:" + StpUtil.isLogin() + " (" + StpUtil.getLoginId("") + ")</p>" +
|
||||||
"<p>当前会话是否登录:" + StpUtil.isLogin() + "</p>" +
|
"<p> " +
|
||||||
"<p><a href=\"javascript:location.href='/sso/login?back=' + encodeURIComponent(location.href);\">登录</a> " +
|
"<a href='/sso/login?back=/'>登录</a> - " +
|
||||||
"<a href=\"javascript:location.href='" + solUrl + "?back=' + encodeURIComponent(location.href);\">注销</a> </p>";
|
"<a href='/sso/logoutByAlone?back=/'>单应用注销</a> - " +
|
||||||
|
"<a href='/sso/logout?back=self&singleDeviceIdLogout=true'>单浏览器注销</a> - " +
|
||||||
|
"<a href='/sso/logout?back=self'>全端注销</a> - " +
|
||||||
|
"<a href='/sso/myInfo' target='_blank'>账号资料</a>" +
|
||||||
|
"</p>";
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SSO-Client端:处理所有SSO相关请求
|
* SSO-Client端:处理所有SSO相关请求
|
||||||
* http://{host}:{port}/sso/login -- Client端登录地址,接受参数:back=登录后的跳转地址
|
* http://{host}:{port}/sso/login -- Client 端登录地址
|
||||||
* http://{host}:{port}/sso/logout -- Client端单点注销地址(isSlo=true时打开),接受参数:back=注销后的跳转地址
|
* http://{host}:{port}/sso/logout -- Client 端注销地址(isSlo=true时打开)
|
||||||
* http://{host}:{port}/sso/logoutCall -- Client端单点注销回调地址(isSlo=true时打开),此接口为框架回调,开发者无需关心
|
* http://{host}:{port}/sso/pushC -- Client 端接收消息推送地址
|
||||||
*/
|
*/
|
||||||
@RequestMapping("/sso/*")
|
@RequestMapping("/sso/*")
|
||||||
public Object ssoRequest() {
|
public Object ssoRequest() {
|
||||||
@ -45,11 +50,32 @@ public class SsoClientController {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 全局异常拦截
|
// 当前应用独自注销 (不退出其它应用)
|
||||||
@ExceptionHandler
|
@RequestMapping("/sso/logoutByAlone")
|
||||||
public SaResult handlerException(Exception e) {
|
public Object logoutByAlone() {
|
||||||
e.printStackTrace();
|
StpUtil.logout();
|
||||||
return SaResult.error(e.getMessage());
|
return SaSsoClientProcessor.instance._ssoLogoutBack(SaHolder.getRequest(), SaHolder.getResponse());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查询我的账号信息:sso-client 前端 -> sso-center 后端 -> sso-server 后端
|
||||||
|
@RequestMapping("/sso/myInfo")
|
||||||
|
public Object myInfo() {
|
||||||
|
// 如果尚未登录
|
||||||
|
if( ! StpUtil.isLogin()) {
|
||||||
|
return "尚未登录,无法获取";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取本地 loginId
|
||||||
|
Object loginId = StpUtil.getLoginId();
|
||||||
|
|
||||||
|
// 推送消息
|
||||||
|
SaSsoMessage message = new SaSsoMessage();
|
||||||
|
message.setType("userinfo");
|
||||||
|
message.set("loginId", loginId);
|
||||||
|
SaResult result = SaSsoClientUtil.pushMessageAsSaResult(message);
|
||||||
|
|
||||||
|
// 返回给前端
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,18 +6,17 @@ server:
|
|||||||
sa-token:
|
sa-token:
|
||||||
# SSO-相关配置
|
# SSO-相关配置
|
||||||
sso-client:
|
sso-client:
|
||||||
|
# 应用标识
|
||||||
|
client: sso-client2
|
||||||
# SSO-Server 端主机地址
|
# SSO-Server 端主机地址
|
||||||
server-url: http://sa-sso-server.com:9000
|
server-url: http://sa-sso-server.com:9000
|
||||||
# 在 sso-server 端前后端分离时打开这个(上面的不要注释,auth-url 配置项和 server-url 要同时存在)
|
# 在 sso-server 端前后端分离时需要单独配置 auth-url 参数(上面的不要注释,auth-url 配置项和 server-url 要同时存在)
|
||||||
# auth-url: http://127.0.0.1:8848/sa-token-demo-sso-server-h5/sso-auth.html
|
# auth-url: http://127.0.0.1:8848/sa-token-demo-sso-server-h5/sso-auth.html
|
||||||
|
# API 接口调用秘钥 (单点注销时会用到)
|
||||||
client: sso-client2
|
|
||||||
|
|
||||||
sign:
|
|
||||||
# API 接口调用秘钥
|
|
||||||
secret-key: SSO-C2-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
secret-key: SSO-C2-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||||
|
|
||||||
# 配置Sa-Token单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis)
|
# 配置 Sa-Token 单独使用的Redis连接(此处需要和 SSO-Server 端连接同一个 Redis)
|
||||||
|
# 注:使用 alone-redis 需要在 pom.xml 引入 sa-token-alone-redis 依赖
|
||||||
alone-redis:
|
alone-redis:
|
||||||
# Redis数据库索引
|
# Redis数据库索引
|
||||||
database: 1
|
database: 1
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
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>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>cn.dev33</groupId>
|
<groupId>cn.dev33</groupId>
|
||||||
<artifactId>sa-token-demo-sso3-client-test2</artifactId>
|
<artifactId>sa-token-demo-sso3-client-anon</artifactId>
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<!-- SpringBoot -->
|
<!-- SpringBoot -->
|
||||||
@ -53,15 +53,15 @@
|
|||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-pool2</artifactId>
|
<artifactId>commons-pool2</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Http请求工具 -->
|
<!-- Sa-Token 插件:整合 Forest 请求工具 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.dtflys.forest</groupId>
|
<groupId>cn.dev33</groupId>
|
||||||
<artifactId>forest-spring-boot-starter</artifactId>
|
<artifactId>sa-token-forest</artifactId>
|
||||||
<version>1.5.26</version>
|
<version>${sa-token.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package com.pj;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.sso.SaSsoManager;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class SaSso3ClientAnonApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(SaSso3ClientAnonApplication.class, args);
|
||||||
|
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("---------------------- Sa-Token SSO 模式三 (匿名应用) Client 端启动成功 ----------------------");
|
||||||
|
System.out.println("配置信息:" + SaSsoManager.getClientConfig());
|
||||||
|
System.out.println("测试访问应用端一: http://sa-sso-client1.com:9006");
|
||||||
|
System.out.println("测试访问应用端二: http://sa-sso-client2.com:9006");
|
||||||
|
System.out.println("测试访问应用端三: http://sa-sso-client3.com:9006");
|
||||||
|
System.out.println("测试前需要根据官网文档修改 hosts 文件,测试账号密码:sa / 123456");
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.pj.sso;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.util.SaResult;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局异常处理
|
||||||
|
* @author click33
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@RestControllerAdvice
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
// 全局异常拦截
|
||||||
|
@ExceptionHandler
|
||||||
|
public SaResult handlerException(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return SaResult.error(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
package com.pj.sso;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.context.SaHolder;
|
||||||
|
import cn.dev33.satoken.sso.message.SaSsoMessage;
|
||||||
|
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
|
||||||
|
import cn.dev33.satoken.sso.template.SaSsoClientTemplate;
|
||||||
|
import cn.dev33.satoken.sso.template.SaSsoClientUtil;
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import cn.dev33.satoken.util.SaResult;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sa-Token-SSO Client端 Controller
|
||||||
|
* @author click33
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
public class SsoClientController {
|
||||||
|
|
||||||
|
// 首页
|
||||||
|
@RequestMapping("/")
|
||||||
|
public String index() {
|
||||||
|
String str = "<h2>Sa-Token SSO-Client 应用端 (模式三-匿名应用)</h2>" +
|
||||||
|
"<p>当前会话是否登录:" + StpUtil.isLogin() + " (" + StpUtil.getLoginId("") + ")</p>" +
|
||||||
|
"<p> " +
|
||||||
|
"<a href='/sso/login?back=/'>登录</a> - " +
|
||||||
|
"<a href='/sso/logoutByAlone?back=/'>单应用注销</a> - " +
|
||||||
|
"<a href='/sso/logout?back=self&singleDeviceIdLogout=true'>单浏览器注销</a> - " +
|
||||||
|
"<a href='/sso/logout?back=self'>全端注销</a> - " +
|
||||||
|
"<a href='/sso/myInfo' target='_blank'>账号资料</a>" +
|
||||||
|
"</p>";
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SSO-Client端:处理所有SSO相关请求
|
||||||
|
* http://{host}:{port}/sso/login -- Client 端登录地址
|
||||||
|
* http://{host}:{port}/sso/logout -- Client 端注销地址(isSlo=true时打开)
|
||||||
|
* http://{host}:{port}/sso/pushC -- Client 端接收消息推送地址
|
||||||
|
*/
|
||||||
|
@RequestMapping("/sso/*")
|
||||||
|
public Object ssoRequest() {
|
||||||
|
return SaSsoClientProcessor.instance.dister();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置SSO相关参数
|
||||||
|
@Autowired
|
||||||
|
private void configSso(SaSsoClientTemplate ssoClientTemplate) {
|
||||||
|
// // 将 centerId 转换为 loginId 的函数
|
||||||
|
// ssoClientTemplate.strategy.convertCenterIdToLoginId = (centerId) -> {
|
||||||
|
// return "Stu" + centerId;
|
||||||
|
// };
|
||||||
|
// // 将 loginId 转换为 centerId 的函数
|
||||||
|
// ssoClientTemplate.strategy.convertLoginIdToCenterId = (loginId) -> {
|
||||||
|
// return loginId.toString().substring(3);
|
||||||
|
// };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当前应用独自注销 (不退出其它应用)
|
||||||
|
@RequestMapping("/sso/logoutByAlone")
|
||||||
|
public Object logoutByAlone() {
|
||||||
|
StpUtil.logout();
|
||||||
|
return SaSsoClientProcessor.instance._ssoLogoutBack(SaHolder.getRequest(), SaHolder.getResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询我的账号信息:sso-client 前端 -> sso-center 后端 -> sso-server 后端
|
||||||
|
@RequestMapping("/sso/myInfo")
|
||||||
|
public Object myInfo() {
|
||||||
|
// 如果尚未登录
|
||||||
|
if( ! StpUtil.isLogin()) {
|
||||||
|
return "尚未登录,无法获取";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取本地 loginId 对应的认证中心 centerId
|
||||||
|
Object centerId = SaSsoClientUtil.getSsoTemplate().strategy.convertLoginIdToCenterId.run(StpUtil.getLoginId());
|
||||||
|
|
||||||
|
// 推送消息
|
||||||
|
SaSsoMessage message = new SaSsoMessage();
|
||||||
|
message.setType("userinfo");
|
||||||
|
message.set("loginId", centerId);
|
||||||
|
SaResult result = SaSsoClientUtil.pushMessageAsSaResult(message);
|
||||||
|
|
||||||
|
// 返回给前端
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,19 +1,21 @@
|
|||||||
# 端口
|
# 端口
|
||||||
server:
|
server:
|
||||||
port: 9032
|
port: 9006
|
||||||
|
|
||||||
# sa-token配置
|
# sa-token配置
|
||||||
sa-token:
|
sa-token:
|
||||||
|
# 配置一个不同的 token-name,以避免在和模式三 demo 一起测试时发生数据覆盖
|
||||||
|
token-name: satoken-client-anon
|
||||||
# sso-client 相关配置
|
# sso-client 相关配置
|
||||||
sso-client:
|
sso-client:
|
||||||
# client 标识
|
# client 标识 匿名应用就是指不配置 client 标识的应用
|
||||||
client: sso-client3-test2
|
# client: sso-client3
|
||||||
# sso-server 端主机地址
|
# sso-server 端主机地址
|
||||||
server-url: http://sa-sso-server.com:9000
|
server-url: http://sa-sso-server.com:9000
|
||||||
# 使用 Http 请求校验ticket (模式三)
|
# 使用 Http 请求校验ticket (模式三)
|
||||||
is-http: true
|
is-http: true
|
||||||
|
# 是否在登录时注册单点登录回调接口 (匿名应用想要参与单点注销必须打开这个)
|
||||||
sign:
|
reg-logout-call: true
|
||||||
# API 接口调用秘钥
|
# API 接口调用秘钥
|
||||||
secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||||
|
|
||||||
@ -21,7 +23,7 @@ spring:
|
|||||||
# 配置 Redis 连接 (此处与SSO-Server端连接不同的Redis)
|
# 配置 Redis 连接 (此处与SSO-Server端连接不同的Redis)
|
||||||
redis:
|
redis:
|
||||||
# Redis数据库索引
|
# Redis数据库索引
|
||||||
database: 4
|
database: 6
|
||||||
# Redis服务器地址
|
# Redis服务器地址
|
||||||
host: 127.0.0.1
|
host: 127.0.0.1
|
||||||
# Redis服务器连接端口
|
# Redis服务器连接端口
|
||||||
@ -8,15 +8,17 @@ public class SaSsoClientNoSdkApplication {
|
|||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(SaSsoClientNoSdkApplication.class, args);
|
SpringApplication.run(SaSsoClientNoSdkApplication.class, args);
|
||||||
System.out.println("\nSa-Token SSO模式三 Client端 (无SDK版本) 启动成功");
|
|
||||||
|
|
||||||
System.out.println();
|
System.out.println();
|
||||||
System.out.println("---------------------- Sa-Token SSO 模式三 NoSdk 模式 demo 启动成功 ----------------------");
|
System.out.println("---------------------- Sa-Token SSO 模式三 (NoSdk版) demo 启动成功 ----------------------");
|
||||||
System.out.println("测试访问应用端一: http://sa-sso-client1.com:9004");
|
System.out.println("测试访问应用端一: http://sa-sso-client1.com:9004");
|
||||||
System.out.println("测试访问应用端二: http://sa-sso-client2.com:9004");
|
System.out.println("测试访问应用端二: http://sa-sso-client2.com:9004");
|
||||||
System.out.println("测试访问应用端三: http://sa-sso-client3.com:9004");
|
System.out.println("测试访问应用端三: http://sa-sso-client3.com:9004");
|
||||||
System.out.println("测试前需要根据官网文档修改hosts文件,测试账号密码:sa / 123456");
|
System.out.println("测试前需要根据官网文档修改hosts文件,测试账号密码:sa / 123456");
|
||||||
System.out.println();
|
System.out.println();
|
||||||
|
|
||||||
|
System.err.println("自 v1.43.0 版本起,Sa-Token SSO 不再维护 NoSdk 示例,此项目仅做留档");
|
||||||
|
System.err.println("如您需要非 Sa-Token 技术栈项目接入 SSO-Server 认证中心,请参考 ReSdk 版本示例");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
<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-sso3-client-resdk</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<!-- SpringBoot -->
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.5.14</version>
|
||||||
|
<relativePath/>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<!-- 定义 Sa-Token 版本号 -->
|
||||||
|
<properties>
|
||||||
|
<sa-token.version>1.42.0</sa-token.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- SpringBoot依赖 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Sa-Token 权限认证, 在线文档:https://sa-token.cc/ -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.dev33</groupId>
|
||||||
|
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||||
|
<version>${sa-token.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Sa-Token 插件:整合SSO -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.dev33</groupId>
|
||||||
|
<artifactId>sa-token-sso</artifactId>
|
||||||
|
<version>${sa-token.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Sa-Token 插件:整合 Forest 请求工具 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.dev33</groupId>
|
||||||
|
<artifactId>sa-token-forest</artifactId>
|
||||||
|
<version>${sa-token.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
||||||
@ -1,23 +1,21 @@
|
|||||||
package com.pj;
|
package com.pj;
|
||||||
|
|
||||||
import cn.dev33.satoken.sso.SaSsoManager;
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class SaSso3ClientTest2Application {
|
public class SaSsoClientReSdkApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(SaSso3ClientTest2Application.class, args);
|
SpringApplication.run(SaSsoClientReSdkApplication.class, args);
|
||||||
|
|
||||||
System.out.println();
|
System.out.println();
|
||||||
System.out.println("---------------------- Sa-Token SSO 模式三 Client 端启动成功 ----------------------");
|
System.out.println("---------------------- Sa-Token SSO 模式三 (ReSdk版) demo 启动成功 ----------------------");
|
||||||
System.out.println("配置信息:" + SaSsoManager.getClientConfig());
|
System.out.println("测试访问应用端一: http://sa-sso-client1.com:9005");
|
||||||
System.out.println("测试访问应用端一: http://sa-sso-client1.com:9032");
|
System.out.println("测试访问应用端二: http://sa-sso-client2.com:9005");
|
||||||
System.out.println("测试访问应用端二: http://sa-sso-client2.com:9032");
|
System.out.println("测试访问应用端三: http://sa-sso-client3.com:9005");
|
||||||
System.out.println("测试访问应用端三: http://sa-sso-client3.com:9032");
|
|
||||||
System.out.println("测试前需要根据官网文档修改hosts文件,测试账号密码:sa / 123456");
|
System.out.println("测试前需要根据官网文档修改hosts文件,测试账号密码:sa / 123456");
|
||||||
System.out.println();
|
System.out.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package com.pj.resdk;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
import javax.servlet.http.HttpSessionEvent;
|
||||||
|
import javax.servlet.http.HttpSessionListener;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录所有已创建的 HttpSession 对象
|
||||||
|
*
|
||||||
|
* <b> 此种方式有性能问题,仅做demo示例,真实项目中请更换为其它方案记录用户会话数据 </b>
|
||||||
|
*
|
||||||
|
* @author click33
|
||||||
|
* @since 2022-4-30
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class MyHttpSessionHolder implements HttpSessionListener {
|
||||||
|
|
||||||
|
public static List<HttpSession> sessionList = new ArrayList<>();
|
||||||
|
|
||||||
|
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
|
||||||
|
sessionList.add(httpSessionEvent.getSession());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
|
||||||
|
HttpSession session = httpSessionEvent.getSession();
|
||||||
|
sessionList.remove(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
package com.pj.resdk;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.spring.SpringMVCUtil;
|
||||||
|
import cn.dev33.satoken.stp.StpLogic;
|
||||||
|
import cn.dev33.satoken.stp.parameter.SaLogoutParameter;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会话对象 - httpSession 版
|
||||||
|
*
|
||||||
|
* @author click33
|
||||||
|
* @since 2025/5/6
|
||||||
|
*/
|
||||||
|
public class StpLogicForHttpSession extends StpLogic {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化 StpLogic, 并指定账号类型
|
||||||
|
*
|
||||||
|
* @param type /
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public StpLogicForHttpSession(String type) {
|
||||||
|
super(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断当前会话是否已登录
|
||||||
|
@Override
|
||||||
|
public boolean isLogin() {
|
||||||
|
|
||||||
|
return SpringMVCUtil.getRequest().getSession().getAttribute("userId") != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前会话的登录ID
|
||||||
|
@Override
|
||||||
|
public Object getLoginId() {
|
||||||
|
Object userId = SpringMVCUtil.getRequest().getSession().getAttribute("userId");
|
||||||
|
if(userId == null) {
|
||||||
|
throw new RuntimeException("当前会话未登录");
|
||||||
|
}
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前登录设备 id
|
||||||
|
@Override
|
||||||
|
public String getLoginDeviceId() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当前会话注销
|
||||||
|
@Override
|
||||||
|
public void logout(SaLogoutParameter logoutParameter) {
|
||||||
|
SpringMVCUtil.getRequest().getSession().removeAttribute("userId");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当前账号id注销
|
||||||
|
@Override
|
||||||
|
public void _logout(Object loginId, SaLogoutParameter logoutParameter) {
|
||||||
|
System.out.println("--- 注销账号id:" + loginId);
|
||||||
|
for (HttpSession session: MyHttpSessionHolder.sessionList) {
|
||||||
|
Object userId = session.getAttribute("userId");
|
||||||
|
if(Objects.equals(String.valueOf(userId), String.valueOf(loginId))) {
|
||||||
|
session.removeAttribute("userId");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.pj.sso;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.util.SaResult;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局异常处理
|
||||||
|
* @author click33
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@RestControllerAdvice
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
// 全局异常拦截
|
||||||
|
@ExceptionHandler
|
||||||
|
public SaResult handlerException(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return SaResult.error(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
package com.pj.sso;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.context.SaHolder;
|
||||||
|
import cn.dev33.satoken.spring.SpringMVCUtil;
|
||||||
|
import cn.dev33.satoken.sso.message.SaSsoMessage;
|
||||||
|
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
|
||||||
|
import cn.dev33.satoken.sso.template.SaSsoClientTemplate;
|
||||||
|
import cn.dev33.satoken.sso.template.SaSsoClientUtil;
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import cn.dev33.satoken.util.SaResult;
|
||||||
|
import com.pj.resdk.StpLogicForHttpSession;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSO Client端 Controller
|
||||||
|
* @author click33
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
public class SsoClientController {
|
||||||
|
|
||||||
|
// SSO-Client端:首页
|
||||||
|
@RequestMapping("/")
|
||||||
|
public String index(HttpSession session) {
|
||||||
|
boolean isLogin = session.getAttribute("userId") != null;
|
||||||
|
Object loginId = session.getAttribute("userId");
|
||||||
|
String str = "<h2>Sa-Token SSO-Client 应用端 (模式三-ReSdk)</h2>" +
|
||||||
|
"<p>当前会话是否登录:" + isLogin + " (" + loginId + ")</p>" +
|
||||||
|
"<p> " +
|
||||||
|
"<a href='/sso/login?back=/'>登录</a> - " +
|
||||||
|
"<a href='/sso/logoutByAlone?back=/'>单应用注销</a> - " +
|
||||||
|
"<a href='/sso/logout?back=self'>全端注销</a> - " +
|
||||||
|
"<a href='/sso/myInfo' target='_blank'>账号资料</a>" +
|
||||||
|
"</p>";
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SSO-Client端:处理所有 SSO 相关请求
|
||||||
|
* http://{host}:{port}/sso/login -- Client 端登录地址
|
||||||
|
* http://{host}:{port}/sso/logout -- Client 端注销地址(isSlo=true时打开)
|
||||||
|
* http://{host}:{port}/sso/pushC -- Client 端接收消息推送地址
|
||||||
|
*/
|
||||||
|
@RequestMapping("/sso/*")
|
||||||
|
public Object ssoLogin() {
|
||||||
|
return SaSsoClientProcessor.instance.dister();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当前应用独自注销 (不退出其它应用)
|
||||||
|
@RequestMapping("/sso/logoutByAlone")
|
||||||
|
public Object logoutByAlone(HttpSession session) {
|
||||||
|
session.removeAttribute("userId");
|
||||||
|
return SaSsoClientProcessor.instance._ssoLogoutBack(SaHolder.getRequest(), SaHolder.getResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置SSO相关参数
|
||||||
|
@Autowired
|
||||||
|
private void configSso(SaSsoClientTemplate ssoClientTemplate) {
|
||||||
|
|
||||||
|
// 自定义底层使用的会话操作对象
|
||||||
|
ssoClientTemplate.setStpLogic(new StpLogicForHttpSession(StpUtil.TYPE));
|
||||||
|
|
||||||
|
// 自定义校验 ticket 返回值的处理逻辑 (每次从认证中心获取校验 ticket 的结果后调用)
|
||||||
|
ssoClientTemplate.strategy.ticketResultHandle = (ctr, back) -> {
|
||||||
|
HttpSession session = SpringMVCUtil.getRequest().getSession();
|
||||||
|
session.setAttribute("userId", ctr.loginId);
|
||||||
|
return SaHolder.getResponse().redirect(back);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询我的账号信息:sso-client 前端 -> sso-center 后端 -> sso-server 后端
|
||||||
|
@RequestMapping("/sso/myInfo")
|
||||||
|
public Object myInfo(HttpSession session) {
|
||||||
|
// 如果尚未登录
|
||||||
|
if(session.getAttribute("userId") == null) {
|
||||||
|
return "尚未登录,无法获取";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 推送消息
|
||||||
|
SaSsoMessage message = new SaSsoMessage();
|
||||||
|
message.setType("userinfo");
|
||||||
|
message.set("loginId", session.getAttribute("userId"));
|
||||||
|
SaResult result = SaSsoClientUtil.pushMessageAsSaResult(message);
|
||||||
|
|
||||||
|
// 返回给前端
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
# 端口
|
||||||
|
server:
|
||||||
|
port: 9005
|
||||||
|
|
||||||
|
# sa-token 配置
|
||||||
|
sa-token:
|
||||||
|
# 是否打印操作日志
|
||||||
|
is-log: true
|
||||||
|
# sso-client 相关配置
|
||||||
|
sso-client:
|
||||||
|
# client 标识
|
||||||
|
client: sso-client3-resdk
|
||||||
|
# sso-server 端主机地址
|
||||||
|
server-url: http://sa-sso-server.com:9000
|
||||||
|
# 使用 Http 请求校验ticket (模式三)
|
||||||
|
is-http: true
|
||||||
|
# API 接口调用秘钥
|
||||||
|
secret-key: SSO-C3-ReSdk-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||||
@ -1,78 +0,0 @@
|
|||||||
package com.pj.sso;
|
|
||||||
|
|
||||||
import cn.dev33.satoken.sso.config.SaSsoClientConfig;
|
|
||||||
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
|
|
||||||
import cn.dev33.satoken.sso.template.SaSsoUtil;
|
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
|
||||||
import cn.dev33.satoken.util.SaResult;
|
|
||||||
import com.dtflys.forest.Forest;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sa-Token-SSO Client端 Controller
|
|
||||||
* @author click33
|
|
||||||
*/
|
|
||||||
@RestController
|
|
||||||
public class SsoClientController {
|
|
||||||
|
|
||||||
// SSO-Client端:首页
|
|
||||||
@RequestMapping("/")
|
|
||||||
public String index() {
|
|
||||||
String str = "<h2>Sa-Token SSO-Client 应用端</h2>" +
|
|
||||||
"<p>当前会话是否登录:" + StpUtil.isLogin() + "</p>" +
|
|
||||||
"<p><a href=\"javascript:location.href='/sso/login?back=' + encodeURIComponent(location.href);\">登录</a>" +
|
|
||||||
" <a href='/sso/logout?back=self'>注销</a></p>";
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SSO-Client端:处理所有SSO相关请求
|
|
||||||
* http://{host}:{port}/sso/login -- Client端登录地址,接受参数:back=登录后的跳转地址
|
|
||||||
* http://{host}:{port}/sso/logout -- Client端单点注销地址(isSlo=true时打开),接受参数:back=注销后的跳转地址
|
|
||||||
* http://{host}:{port}/sso/logoutCall -- Client端单点注销回调地址(isSlo=true时打开),此接口为框架回调,开发者无需关心
|
|
||||||
*/
|
|
||||||
@RequestMapping("/sso/*")
|
|
||||||
public Object ssoRequest() {
|
|
||||||
return SaSsoClientProcessor.instance.dister();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 配置SSO相关参数
|
|
||||||
@Autowired
|
|
||||||
private void configSso(SaSsoClientConfig ssoClient) {
|
|
||||||
// 配置Http请求处理器
|
|
||||||
ssoClient.sendHttp = url -> {
|
|
||||||
System.out.println("------ 发起请求:" + url);
|
|
||||||
String resStr = Forest.get(url).executeAsString();
|
|
||||||
System.out.println("------ 请求结果:" + resStr);
|
|
||||||
return resStr;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询我的账号信息
|
|
||||||
@RequestMapping("/sso/myInfo")
|
|
||||||
public Object myInfo() {
|
|
||||||
// 组织请求参数
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("apiType", "userinfo");
|
|
||||||
map.put("loginId", StpUtil.getLoginId());
|
|
||||||
|
|
||||||
// 发起请求
|
|
||||||
Object resData = SaSsoUtil.getData(map);
|
|
||||||
System.out.println("sso-server 返回的信息:" + resData);
|
|
||||||
return resData;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 全局异常拦截
|
|
||||||
@ExceptionHandler
|
|
||||||
public SaResult handlerException(Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return SaResult.error(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -16,7 +16,7 @@ public class SaSso3ClientApplication {
|
|||||||
System.out.println("测试访问应用端一: http://sa-sso-client1.com:9003");
|
System.out.println("测试访问应用端一: http://sa-sso-client1.com:9003");
|
||||||
System.out.println("测试访问应用端二: http://sa-sso-client2.com:9003");
|
System.out.println("测试访问应用端二: http://sa-sso-client2.com:9003");
|
||||||
System.out.println("测试访问应用端三: http://sa-sso-client3.com:9003");
|
System.out.println("测试访问应用端三: http://sa-sso-client3.com:9003");
|
||||||
System.out.println("测试前需要根据官网文档修改hosts文件,测试账号密码:sa / 123456");
|
System.out.println("测试前需要根据官网文档修改 hosts 文件,测试账号密码:sa / 123456");
|
||||||
System.out.println();
|
System.out.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,19 +2,18 @@ package com.pj.h5;
|
|||||||
|
|
||||||
import cn.dev33.satoken.sso.model.SaCheckTicketResult;
|
import cn.dev33.satoken.sso.model.SaCheckTicketResult;
|
||||||
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
|
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
|
||||||
import cn.dev33.satoken.sso.template.SaSsoUtil;
|
import cn.dev33.satoken.sso.template.SaSsoClientUtil;
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
||||||
import cn.dev33.satoken.util.SaResult;
|
import cn.dev33.satoken.util.SaResult;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 前后台分离架构下集成SSO所需的代码 (SSO-Client端)
|
* 前后台分离架构下集成SSO所需的代码 (SSO-Client端)
|
||||||
* <p>(注:如果不需要前后端分离架构下集成SSO,可删除此包下所有代码)</p>
|
* <p>(注:如果不需要前后端分离架构下集成SSO,可删除此包下所有代码)</p>
|
||||||
* @author click33
|
|
||||||
*
|
*
|
||||||
|
* @author click33
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
public class H5Controller {
|
public class H5Controller {
|
||||||
@ -28,7 +27,7 @@ public class H5Controller {
|
|||||||
// 返回SSO认证中心登录地址
|
// 返回SSO认证中心登录地址
|
||||||
@RequestMapping("/sso/getSsoAuthUrl")
|
@RequestMapping("/sso/getSsoAuthUrl")
|
||||||
public SaResult getSsoAuthUrl(String clientLoginUrl) {
|
public SaResult getSsoAuthUrl(String clientLoginUrl) {
|
||||||
String serverAuthUrl = SaSsoUtil.buildServerAuthUrl(clientLoginUrl, "");
|
String serverAuthUrl = SaSsoClientUtil.buildServerAuthUrl(clientLoginUrl, "");
|
||||||
return SaResult.data(serverAuthUrl);
|
return SaResult.data(serverAuthUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,11 +42,4 @@ public class H5Controller {
|
|||||||
return SaResult.data(StpUtil.getTokenValue());
|
return SaResult.data(StpUtil.getTokenValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 全局异常拦截
|
|
||||||
@ExceptionHandler
|
|
||||||
public SaResult handlerException(Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return SaResult.error(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Sa-Token 权限认证] 配置类 (解决跨域问题)
|
* [Sa-Token 权限认证] 配置类
|
||||||
*
|
*
|
||||||
* @author click33
|
* @author click33
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.pj.sso;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.util.SaResult;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局异常处理
|
||||||
|
* @author click33
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@RestControllerAdvice
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
// 全局异常拦截
|
||||||
|
@ExceptionHandler
|
||||||
|
public SaResult handlerException(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return SaResult.error(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,18 +1,16 @@
|
|||||||
package com.pj.sso;
|
package com.pj.sso;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.context.SaHolder;
|
||||||
|
import cn.dev33.satoken.sso.message.SaSsoMessage;
|
||||||
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
|
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
|
||||||
import cn.dev33.satoken.sso.template.SaSsoClientTemplate;
|
import cn.dev33.satoken.sso.template.SaSsoClientTemplate;
|
||||||
import cn.dev33.satoken.sso.template.SaSsoUtil;
|
import cn.dev33.satoken.sso.template.SaSsoClientUtil;
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import cn.dev33.satoken.util.SaResult;
|
import cn.dev33.satoken.util.SaResult;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sa-Token-SSO Client端 Controller
|
* Sa-Token-SSO Client端 Controller
|
||||||
* @author click33
|
* @author click33
|
||||||
@ -23,18 +21,23 @@ public class SsoClientController {
|
|||||||
// SSO-Client端:首页
|
// SSO-Client端:首页
|
||||||
@RequestMapping("/")
|
@RequestMapping("/")
|
||||||
public String index() {
|
public String index() {
|
||||||
String str = "<h2>Sa-Token SSO-Client 应用端</h2>" +
|
String str = "<h2>Sa-Token SSO-Client 应用端 (模式三)</h2>" +
|
||||||
"<p>当前会话是否登录:" + StpUtil.isLogin() + " (" + StpUtil.getLoginId("") + ")</p>" +
|
"<p>当前会话是否登录:" + StpUtil.isLogin() + " (" + StpUtil.getLoginId("") + ")</p>" +
|
||||||
"<p><a href=\"javascript:location.href='/sso/login?back=' + encodeURIComponent(location.href);\">登录</a>" +
|
"<p> " +
|
||||||
" <a href='/sso/logout?back=self'>注销</a></p>";
|
"<a href='/sso/login?back=/'>登录</a> - " +
|
||||||
|
"<a href='/sso/logoutByAlone?back=/'>单应用注销</a> - " +
|
||||||
|
"<a href='/sso/logout?back=self&singleDeviceIdLogout=true'>单浏览器注销</a> - " +
|
||||||
|
"<a href='/sso/logout?back=self'>全端注销</a> - " +
|
||||||
|
"<a href='/sso/myInfo' target='_blank'>账号资料</a>" +
|
||||||
|
"</p>";
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SSO-Client端:处理所有SSO相关请求
|
* SSO-Client端:处理所有SSO相关请求
|
||||||
* http://{host}:{port}/sso/login -- Client端登录地址,接受参数:back=登录后的跳转地址
|
* http://{host}:{port}/sso/login -- Client 端登录地址
|
||||||
* http://{host}:{port}/sso/logout -- Client端单点注销地址(isSlo=true时打开),接受参数:back=注销后的跳转地址
|
* http://{host}:{port}/sso/logout -- Client 端注销地址(isSlo=true时打开)
|
||||||
* http://{host}:{port}/sso/logoutCall -- Client端单点注销回调地址(isSlo=true时打开),此接口为框架回调,开发者无需关心
|
* http://{host}:{port}/sso/pushC -- Client 端接收消息推送地址
|
||||||
*/
|
*/
|
||||||
@RequestMapping("/sso/*")
|
@RequestMapping("/sso/*")
|
||||||
public Object ssoRequest() {
|
public Object ssoRequest() {
|
||||||
@ -44,36 +47,35 @@ public class SsoClientController {
|
|||||||
// 配置SSO相关参数
|
// 配置SSO相关参数
|
||||||
@Autowired
|
@Autowired
|
||||||
private void configSso(SaSsoClientTemplate ssoClientTemplate) {
|
private void configSso(SaSsoClientTemplate ssoClientTemplate) {
|
||||||
// 将 centerId 转换为 loginId 的函数
|
|
||||||
ssoClientTemplate.strategy.convertCenterIdToLoginId = (centerId) -> {
|
|
||||||
return "Stu_" + centerId;
|
|
||||||
};
|
|
||||||
// 将 loginId 转换为 centerId 的函数
|
|
||||||
ssoClientTemplate.strategy.convertLoginIdToCenterId = (loginId) -> {
|
|
||||||
return loginId.toString().substring(4);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询我的账号信息
|
// 当前应用独自注销 (不退出其它应用)
|
||||||
|
@RequestMapping("/sso/logoutByAlone")
|
||||||
|
public Object logoutByAlone() {
|
||||||
|
StpUtil.logout();
|
||||||
|
return SaSsoClientProcessor.instance._ssoLogoutBack(SaHolder.getRequest(), SaHolder.getResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询我的账号信息:sso-client 前端 -> sso-center 后端 -> sso-server 后端
|
||||||
@RequestMapping("/sso/myInfo")
|
@RequestMapping("/sso/myInfo")
|
||||||
public Object myInfo() {
|
public Object myInfo() {
|
||||||
// 组织请求参数
|
// 如果尚未登录
|
||||||
Map<String, Object> map = new HashMap<>();
|
if( ! StpUtil.isLogin()) {
|
||||||
map.put("apiType", "userinfo");
|
return "尚未登录,无法获取";
|
||||||
map.put("loginId", StpUtil.getLoginId());
|
}
|
||||||
|
|
||||||
// 发起请求
|
// 获取本地 loginId
|
||||||
Object resData = SaSsoUtil.getData(map);
|
Object loginId = StpUtil.getLoginId();
|
||||||
System.out.println("sso-server 返回的信息:" + resData);
|
|
||||||
return resData;
|
// 推送消息
|
||||||
|
SaSsoMessage message = new SaSsoMessage();
|
||||||
|
message.setType("userinfo");
|
||||||
|
message.set("loginId", loginId);
|
||||||
|
SaResult result = SaSsoClientUtil.pushMessageAsSaResult(message);
|
||||||
|
|
||||||
|
// 返回给前端
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 全局异常拦截
|
|
||||||
@ExceptionHandler
|
|
||||||
public SaResult handlerException(Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return SaResult.error(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,13 +13,15 @@ sa-token:
|
|||||||
client: sso-client3
|
client: sso-client3
|
||||||
# sso-server 端主机地址
|
# sso-server 端主机地址
|
||||||
server-url: http://sa-sso-server.com:9000
|
server-url: http://sa-sso-server.com:9000
|
||||||
# 使用 Http 请求校验ticket (模式三)
|
# 在 sso-server 端前后端分离时需要单独配置 auth-url 参数(上面的不要注释,auth-url 配置项和 server-url 要同时存在)
|
||||||
|
# auth-url: http://127.0.0.1:8848/sa-token-demo-sso-server-h5/sso-auth.html
|
||||||
|
# 使用 Http 请求校验 ticket (模式三)
|
||||||
is-http: true
|
is-http: true
|
||||||
# API 接口调用秘钥
|
# API 接口调用秘钥
|
||||||
secret-key: SSO-C3-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
secret-key: SSO-C3-kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
# 配置 Redis 连接 (此处与SSO-Server端连接不同的Redis)
|
# 配置 Redis 连接 (此处与 SSO-Server 端连接不同的 Redis)
|
||||||
redis:
|
redis:
|
||||||
# Redis数据库索引
|
# Redis数据库索引
|
||||||
database: 3
|
database: 3
|
||||||
|
|||||||
@ -81,7 +81,7 @@ public class SaSsoClientConfig implements Serializable {
|
|||||||
public Boolean isHttp = false;
|
public Boolean isHttp = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否打开单点注销功能 (为 true 时,接收单点注销回调消息推送)
|
* 是否打开单点注销功能 (为 true 时,开放 /sso/logout 接口,以及接收单点注销回调消息推送)
|
||||||
*/
|
*/
|
||||||
public Boolean isSlo = true;
|
public Boolean isSlo = true;
|
||||||
|
|
||||||
@ -153,14 +153,14 @@ public class SaSsoClientConfig implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return 是否打开单点注销功能 (为 true 时,接收单点注销回调消息推送)
|
* @return 是否打开单点注销功能 (为 true 时,开放 /sso/logout 接口,以及接收单点注销回调消息推送)
|
||||||
*/
|
*/
|
||||||
public Boolean getIsSlo() {
|
public Boolean getIsSlo() {
|
||||||
return isSlo;
|
return isSlo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param isSlo 是否打开单点注销功能 (为 true 时,接收单点注销回调消息推送)
|
* @param isSlo 是否打开单点注销功能 (为 true 时,开放 /sso/logout 接口,以及接收单点注销回调消息推送)
|
||||||
* @return 对象自身
|
* @return 对象自身
|
||||||
*/
|
*/
|
||||||
public SaSsoClientConfig setIsSlo(Boolean isSlo) {
|
public SaSsoClientConfig setIsSlo(Boolean isSlo) {
|
||||||
|
|||||||
@ -82,7 +82,7 @@ public class SaSsoServerConfig implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* 是否允许匿名 Client 接入
|
* 是否允许匿名 Client 接入
|
||||||
*/
|
*/
|
||||||
public Boolean allowAnonClient = true;
|
public Boolean allowAnonClient = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 所有允许的授权回调地址,多个用逗号隔开 (不在此列表中的URL将禁止下放ticket) (匿名 client 使用)
|
* 所有允许的授权回调地址,多个用逗号隔开 (不在此列表中的URL将禁止下放ticket) (匿名 client 使用)
|
||||||
|
|||||||
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020-2099 sa-token.cc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package cn.dev33.satoken.sso.function;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.sso.message.SaSsoMessage;
|
||||||
|
import cn.dev33.satoken.sso.template.SaSsoTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 函数式接口:处理 SSO 消息的函数式接口
|
||||||
|
*
|
||||||
|
* <p> 参数:ssoTemplate 模板对象, 要处理的 message 消息 </p>
|
||||||
|
* <p> 返回:任意值 </p>
|
||||||
|
*
|
||||||
|
* @author click33
|
||||||
|
* @since 1.38.0
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface SaSsoMessageHandleFunction {
|
||||||
|
|
||||||
|
Object execute(SaSsoTemplate ssoTemplate, SaSsoMessage message);
|
||||||
|
|
||||||
|
}
|
||||||
@ -27,6 +27,6 @@ import java.util.function.Function;
|
|||||||
* @since 1.38.0
|
* @since 1.38.0
|
||||||
*/
|
*/
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface SendHttpFunction extends Function<String, String> {
|
public interface SendRequestFunction extends Function<String, String> {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -18,7 +18,9 @@ package cn.dev33.satoken.sso.message;
|
|||||||
|
|
||||||
import cn.dev33.satoken.sso.error.SaSsoErrorCode;
|
import cn.dev33.satoken.sso.error.SaSsoErrorCode;
|
||||||
import cn.dev33.satoken.sso.exception.SaSsoException;
|
import cn.dev33.satoken.sso.exception.SaSsoException;
|
||||||
|
import cn.dev33.satoken.sso.function.SaSsoMessageHandleFunction;
|
||||||
import cn.dev33.satoken.sso.message.handle.SaSsoMessageHandle;
|
import cn.dev33.satoken.sso.message.handle.SaSsoMessageHandle;
|
||||||
|
import cn.dev33.satoken.sso.message.handle.SaSsoMessageSimpleHandle;
|
||||||
import cn.dev33.satoken.sso.template.SaSsoTemplate;
|
import cn.dev33.satoken.sso.template.SaSsoTemplate;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@ -68,6 +70,18 @@ public class SaSsoMessageHolder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加指定类型的简单消息处理器
|
||||||
|
*
|
||||||
|
* @param type 要处理的消息类型
|
||||||
|
* @param handle 要执行的方法
|
||||||
|
* @return 对象自身
|
||||||
|
*/
|
||||||
|
public SaSsoMessageHolder addHandle(String type, SaSsoMessageHandleFunction handle) {
|
||||||
|
messageHandleMap.put(type, new SaSsoMessageSimpleHandle(type, handle));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取指定类型的消息处理器
|
* 获取指定类型的消息处理器
|
||||||
*
|
*
|
||||||
|
|||||||
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020-2099 sa-token.cc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package cn.dev33.satoken.sso.message.handle;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.dev33.satoken.sso.function.SaSsoMessageHandleFunction;
|
||||||
|
import cn.dev33.satoken.sso.message.SaSsoMessage;
|
||||||
|
import cn.dev33.satoken.sso.template.SaSsoTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSO 消息处理器 - 简单实现,方便 lambda 表达式编程
|
||||||
|
*
|
||||||
|
* @author click33
|
||||||
|
* @since 1.43.0
|
||||||
|
*/
|
||||||
|
public class SaSsoMessageSimpleHandle implements SaSsoMessageHandle{
|
||||||
|
|
||||||
|
public String type;
|
||||||
|
|
||||||
|
public SaSsoMessageHandleFunction handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSO 消息处理器 - 简单实现,方便 lambda 表达式编程
|
||||||
|
* @param type 要处理的消息类型
|
||||||
|
* @param handle 要执行的方法
|
||||||
|
*/
|
||||||
|
public SaSsoMessageSimpleHandle(String type, SaSsoMessageHandleFunction handle) {
|
||||||
|
this.type = type;
|
||||||
|
this.handle = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所要处理的消息类型
|
||||||
|
*
|
||||||
|
* @return /
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getHandlerType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 具体要执行的处理方法
|
||||||
|
*
|
||||||
|
* @param ssoTemplate /
|
||||||
|
* @param message /
|
||||||
|
* @return /
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object handle(SaSsoTemplate ssoTemplate, SaSsoMessage message){
|
||||||
|
return handle.execute(ssoTemplate, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -16,8 +16,6 @@
|
|||||||
package cn.dev33.satoken.sso.message.handle.client;
|
package cn.dev33.satoken.sso.message.handle.client;
|
||||||
|
|
||||||
|
|
||||||
import cn.dev33.satoken.context.SaHolder;
|
|
||||||
import cn.dev33.satoken.context.model.SaRequest;
|
|
||||||
import cn.dev33.satoken.sso.message.SaSsoMessage;
|
import cn.dev33.satoken.sso.message.SaSsoMessage;
|
||||||
import cn.dev33.satoken.sso.message.handle.SaSsoMessageHandle;
|
import cn.dev33.satoken.sso.message.handle.SaSsoMessageHandle;
|
||||||
import cn.dev33.satoken.sso.name.ParamName;
|
import cn.dev33.satoken.sso.name.ParamName;
|
||||||
@ -56,7 +54,7 @@ public class SaSsoMessageLogoutCallHandle implements SaSsoMessageHandle {
|
|||||||
|
|
||||||
// 1、获取对象
|
// 1、获取对象
|
||||||
SaSsoClientTemplate ssoClientTemplate = (SaSsoClientTemplate) ssoTemplate;
|
SaSsoClientTemplate ssoClientTemplate = (SaSsoClientTemplate) ssoTemplate;
|
||||||
StpLogic stpLogic = ssoClientTemplate.getStpLogic();
|
StpLogic stpLogic = ssoClientTemplate.getStpLogicOrGlobal();
|
||||||
ParamName paramName = ssoClientTemplate.paramName;
|
ParamName paramName = ssoClientTemplate.paramName;
|
||||||
|
|
||||||
// 2、判断当前应用是否开启单点注销功能
|
// 2、判断当前应用是否开启单点注销功能
|
||||||
|
|||||||
@ -55,7 +55,7 @@ public class SaSsoMessageCheckTicketHandle implements SaSsoMessageHandle {
|
|||||||
// 1、获取对象
|
// 1、获取对象
|
||||||
SaSsoServerTemplate ssoServerTemplate = (SaSsoServerTemplate) ssoTemplate;
|
SaSsoServerTemplate ssoServerTemplate = (SaSsoServerTemplate) ssoTemplate;
|
||||||
ParamName paramName = ssoServerTemplate.paramName;
|
ParamName paramName = ssoServerTemplate.paramName;
|
||||||
StpLogic stpLogic = ssoServerTemplate.getStpLogic();
|
StpLogic stpLogic = ssoServerTemplate.getStpLogicOrGlobal();
|
||||||
String client = message.getString(paramName.client);
|
String client = message.getString(paramName.client);
|
||||||
String ticket = message.getValueNotNull(paramName.ticket).toString();
|
String ticket = message.getValueNotNull(paramName.ticket).toString();
|
||||||
String sloCallback = message.getString(paramName.ssoLogoutCall);
|
String sloCallback = message.getString(paramName.ssoLogoutCall);
|
||||||
|
|||||||
@ -65,7 +65,7 @@ public class SaSsoMessageSignoutHandle implements SaSsoMessageHandle {
|
|||||||
String deviceId = message.getString(paramName.deviceId);
|
String deviceId = message.getString(paramName.deviceId);
|
||||||
|
|
||||||
// 4、单点注销
|
// 4、单点注销
|
||||||
SaLogoutParameter logoutParameter = ssoServerTemplate.getStpLogic().createSaLogoutParameter().setDeviceId(deviceId);
|
SaLogoutParameter logoutParameter = ssoServerTemplate.getStpLogicOrGlobal().createSaLogoutParameter().setDeviceId(deviceId);
|
||||||
ssoServerTemplate.ssoLogout(loginId, logoutParameter);
|
ssoServerTemplate.ssoLogout(loginId, logoutParameter);
|
||||||
|
|
||||||
// 5、响应
|
// 5、响应
|
||||||
|
|||||||
@ -164,7 +164,7 @@ public class SaSsoClientProcessor {
|
|||||||
|
|
||||||
// 获取对象
|
// 获取对象
|
||||||
SaRequest req = SaHolder.getRequest();
|
SaRequest req = SaHolder.getRequest();
|
||||||
StpLogic stpLogic = ssoClientTemplate.getStpLogic();
|
StpLogic stpLogic = ssoClientTemplate.getStpLogicOrGlobal();
|
||||||
ParamName paramName = ssoClientTemplate.paramName;
|
ParamName paramName = ssoClientTemplate.paramName;
|
||||||
SaSsoClientConfig ssoConfig = ssoClientTemplate.getClientConfig();
|
SaSsoClientConfig ssoConfig = ssoClientTemplate.getClientConfig();
|
||||||
|
|
||||||
@ -181,7 +181,7 @@ public class SaSsoClientProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 注销当前应用端会话
|
// 注销当前应用端会话
|
||||||
SaLogoutParameter logoutParameter = ssoClientTemplate.getStpLogic().createSaLogoutParameter();
|
SaLogoutParameter logoutParameter = ssoClientTemplate.getStpLogicOrGlobal().createSaLogoutParameter();
|
||||||
stpLogic.logout(loginId, logoutParameter.setDeviceId(deviceId));
|
stpLogic.logout(loginId, logoutParameter.setDeviceId(deviceId));
|
||||||
|
|
||||||
// 响应
|
// 响应
|
||||||
@ -199,7 +199,7 @@ public class SaSsoClientProcessor {
|
|||||||
SaRequest req = SaHolder.getRequest();
|
SaRequest req = SaHolder.getRequest();
|
||||||
SaResponse res = SaHolder.getResponse();
|
SaResponse res = SaHolder.getResponse();
|
||||||
SaSsoClientConfig cfg = ssoClientTemplate.getClientConfig();
|
SaSsoClientConfig cfg = ssoClientTemplate.getClientConfig();
|
||||||
StpLogic stpLogic = ssoClientTemplate.getStpLogic();
|
StpLogic stpLogic = ssoClientTemplate.getStpLogicOrGlobal();
|
||||||
ParamName paramName = ssoClientTemplate.paramName;
|
ParamName paramName = ssoClientTemplate.paramName;
|
||||||
|
|
||||||
// 获取参数
|
// 获取参数
|
||||||
@ -229,7 +229,7 @@ public class SaSsoClientProcessor {
|
|||||||
// 获取对象
|
// 获取对象
|
||||||
SaRequest req = SaHolder.getRequest();
|
SaRequest req = SaHolder.getRequest();
|
||||||
SaResponse res = SaHolder.getResponse();
|
SaResponse res = SaHolder.getResponse();
|
||||||
StpLogic stpLogic = ssoClientTemplate.getStpLogic();
|
StpLogic stpLogic = ssoClientTemplate.getStpLogicOrGlobal();
|
||||||
ParamName paramName = ssoClientTemplate.paramName;
|
ParamName paramName = ssoClientTemplate.paramName;
|
||||||
ApiName apiName = ssoClientTemplate.apiName;
|
ApiName apiName = ssoClientTemplate.apiName;
|
||||||
|
|
||||||
@ -239,8 +239,6 @@ public class SaSsoClientProcessor {
|
|||||||
|
|
||||||
// 1、校验 ticket,获取 loginId 等数据
|
// 1、校验 ticket,获取 loginId 等数据
|
||||||
SaCheckTicketResult ctr = checkTicket(ticket, apiName.ssoLogin);
|
SaCheckTicketResult ctr = checkTicket(ticket, apiName.ssoLogin);
|
||||||
ctr.centerId = ctr.loginId;
|
|
||||||
ctr.loginId = ssoClientTemplate.strategy.convertCenterIdToLoginId.run(ctr.centerId);
|
|
||||||
|
|
||||||
// 2、如果开发者自定义了 ticket 结果值处理函数,则使用自定义的函数
|
// 2、如果开发者自定义了 ticket 结果值处理函数,则使用自定义的函数
|
||||||
if(ssoClientTemplate.strategy.ticketResultHandle != null) {
|
if(ssoClientTemplate.strategy.ticketResultHandle != null) {
|
||||||
@ -263,7 +261,7 @@ public class SaSsoClientProcessor {
|
|||||||
// 获取对象
|
// 获取对象
|
||||||
SaRequest req = SaHolder.getRequest();
|
SaRequest req = SaHolder.getRequest();
|
||||||
SaResponse res = SaHolder.getResponse();
|
SaResponse res = SaHolder.getResponse();
|
||||||
StpLogic stpLogic = ssoClientTemplate.getStpLogic();
|
StpLogic stpLogic = ssoClientTemplate.getStpLogicOrGlobal();
|
||||||
boolean singleDeviceIdLogout = req.isParam(ssoClientTemplate.paramName.singleDeviceIdLogout, "true");
|
boolean singleDeviceIdLogout = req.isParam(ssoClientTemplate.paramName.singleDeviceIdLogout, "true");
|
||||||
|
|
||||||
// 如果未登录,则无需注销
|
// 如果未登录,则无需注销
|
||||||
@ -292,6 +290,16 @@ public class SaSsoClientProcessor {
|
|||||||
return _ssoLogoutBack(req, res);
|
return _ssoLogoutBack(req, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 封装:校验ticket,取出loginId,如果 ticket 无效则抛出异常 (适用于模式二或模式三)
|
||||||
|
*
|
||||||
|
* @param ticket ticket码
|
||||||
|
* @return SaCheckTicketResult
|
||||||
|
*/
|
||||||
|
public SaCheckTicketResult checkTicket(String ticket) {
|
||||||
|
return checkTicket(ticket, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 封装:校验ticket,取出loginId,如果 ticket 无效则抛出异常 (适用于模式二或模式三)
|
* 封装:校验ticket,取出loginId,如果 ticket 无效则抛出异常 (适用于模式二或模式三)
|
||||||
*
|
*
|
||||||
@ -357,6 +365,10 @@ public class SaSsoClientProcessor {
|
|||||||
ctr.remainSessionTimeout = result.get(paramName.remainSessionTimeout, Long.class);
|
ctr.remainSessionTimeout = result.get(paramName.remainSessionTimeout, Long.class);
|
||||||
ctr.result = result;
|
ctr.result = result;
|
||||||
|
|
||||||
|
// 转换 loginId 和 centerId
|
||||||
|
ctr.centerId = ctr.loginId;
|
||||||
|
ctr.loginId = ssoClientTemplate.strategy.convertCenterIdToLoginId.run(ctr.centerId);
|
||||||
|
|
||||||
return ctr;
|
return ctr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,7 +385,7 @@ public class SaSsoClientProcessor {
|
|||||||
// 可能会导致调用失败(注意是可能,而非一定,主要取决于你是否改变了数据读写格式),
|
// 可能会导致调用失败(注意是可能,而非一定,主要取决于你是否改变了数据读写格式),
|
||||||
// 解决方案为:在当前 sso-client 端也按照 sso-server 端的格式重写 SaSsoClientProcessor 里的方法
|
// 解决方案为:在当前 sso-client 端也按照 sso-server 端的格式重写 SaSsoClientProcessor 里的方法
|
||||||
|
|
||||||
StpLogic stpLogic = ssoClientTemplate.getStpLogic();
|
StpLogic stpLogic = ssoClientTemplate.getStpLogicOrGlobal();
|
||||||
TicketModel ticketModel = SaSsoServerProcessor.instance.ssoServerTemplate.checkTicketParamAndDelete(ticket, ssoClientTemplate.getClient());
|
TicketModel ticketModel = SaSsoServerProcessor.instance.ssoServerTemplate.checkTicketParamAndDelete(ticket, ssoClientTemplate.getClient());
|
||||||
|
|
||||||
SaCheckTicketResult ctr = new SaCheckTicketResult();
|
SaCheckTicketResult ctr = new SaCheckTicketResult();
|
||||||
@ -384,6 +396,10 @@ public class SaSsoClientProcessor {
|
|||||||
ctr.remainSessionTimeout = stpLogic.getSessionTimeoutByLoginId(ticketModel.getLoginId());
|
ctr.remainSessionTimeout = stpLogic.getSessionTimeoutByLoginId(ticketModel.getLoginId());
|
||||||
ctr.result = null;
|
ctr.result = null;
|
||||||
|
|
||||||
|
// 转换 loginId 和 centerId
|
||||||
|
ctr.centerId = ctr.loginId;
|
||||||
|
ctr.loginId = ssoClientTemplate.strategy.convertCenterIdToLoginId.run(ctr.centerId);
|
||||||
|
|
||||||
return ctr;
|
return ctr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -101,7 +101,7 @@ public class SaSsoServerProcessor {
|
|||||||
SaRequest req = SaHolder.getRequest();
|
SaRequest req = SaHolder.getRequest();
|
||||||
SaResponse res = SaHolder.getResponse();
|
SaResponse res = SaHolder.getResponse();
|
||||||
SaSsoServerConfig cfg = ssoServerTemplate.getServerConfig();
|
SaSsoServerConfig cfg = ssoServerTemplate.getServerConfig();
|
||||||
StpLogic stpLogic = ssoServerTemplate.getStpLogic();
|
StpLogic stpLogic = ssoServerTemplate.getStpLogicOrGlobal();
|
||||||
ParamName paramName = ssoServerTemplate.paramName;
|
ParamName paramName = ssoServerTemplate.paramName;
|
||||||
|
|
||||||
// 两种情况:
|
// 两种情况:
|
||||||
@ -177,7 +177,7 @@ public class SaSsoServerProcessor {
|
|||||||
// 获取对象
|
// 获取对象
|
||||||
SaRequest req = SaHolder.getRequest();
|
SaRequest req = SaHolder.getRequest();
|
||||||
SaResponse res = SaHolder.getResponse();
|
SaResponse res = SaHolder.getResponse();
|
||||||
StpLogic stpLogic = ssoServerTemplate.getStpLogic();
|
StpLogic stpLogic = ssoServerTemplate.getStpLogicOrGlobal();
|
||||||
Object loginId = stpLogic.getLoginIdDefaultNull();
|
Object loginId = stpLogic.getLoginIdDefaultNull();
|
||||||
boolean singleDeviceIdLogout = req.isParam(ssoServerTemplate.paramName.singleDeviceIdLogout, "true");
|
boolean singleDeviceIdLogout = req.isParam(ssoServerTemplate.paramName.singleDeviceIdLogout, "true");
|
||||||
|
|
||||||
@ -191,7 +191,7 @@ public class SaSsoServerProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 完成
|
// 完成
|
||||||
return SaSsoProcessorHelper.ssoLogoutBack(req, res, ssoServerTemplate.paramName);
|
return _ssoLogoutBack(req, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -228,4 +228,14 @@ public class SaSsoServerProcessor {
|
|||||||
return ssoServerTemplate.handleMessage(message);
|
return ssoServerTemplate.handleMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 封装:单点注销成功后返回结果
|
||||||
|
* @param req SaRequest对象
|
||||||
|
* @param res SaResponse对象
|
||||||
|
* @return 返回结果
|
||||||
|
*/
|
||||||
|
public Object _ssoLogoutBack(SaRequest req, SaResponse res) {
|
||||||
|
return SaSsoProcessorHelper.ssoLogoutBack(req, res, ssoServerTemplate.paramName);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ package cn.dev33.satoken.sso.strategy;
|
|||||||
|
|
||||||
import cn.dev33.satoken.SaManager;
|
import cn.dev33.satoken.SaManager;
|
||||||
import cn.dev33.satoken.fun.SaParamRetFunction;
|
import cn.dev33.satoken.fun.SaParamRetFunction;
|
||||||
import cn.dev33.satoken.sso.function.SendHttpFunction;
|
import cn.dev33.satoken.sso.function.SendRequestFunction;
|
||||||
import cn.dev33.satoken.sso.function.TicketResultHandleFunction;
|
import cn.dev33.satoken.sso.function.TicketResultHandleFunction;
|
||||||
import cn.dev33.satoken.util.SaResult;
|
import cn.dev33.satoken.util.SaResult;
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ public class SaSsoClientStrategy {
|
|||||||
/**
|
/**
|
||||||
* 发送 Http 请求的处理函数
|
* 发送 Http 请求的处理函数
|
||||||
*/
|
*/
|
||||||
public SendHttpFunction sendHttp = url -> {
|
public SendRequestFunction sendHttp = url -> {
|
||||||
return SaManager.getSaHttpTemplate().get(url);
|
return SaManager.getSaHttpTemplate().get(url);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -16,11 +16,12 @@
|
|||||||
package cn.dev33.satoken.sso.strategy;
|
package cn.dev33.satoken.sso.strategy;
|
||||||
|
|
||||||
import cn.dev33.satoken.SaManager;
|
import cn.dev33.satoken.SaManager;
|
||||||
|
import cn.dev33.satoken.fun.SaFunction;
|
||||||
import cn.dev33.satoken.fun.SaParamFunction;
|
import cn.dev33.satoken.fun.SaParamFunction;
|
||||||
import cn.dev33.satoken.sso.function.CheckTicketAppendDataFunction;
|
import cn.dev33.satoken.sso.function.CheckTicketAppendDataFunction;
|
||||||
import cn.dev33.satoken.sso.function.DoLoginHandleFunction;
|
import cn.dev33.satoken.sso.function.DoLoginHandleFunction;
|
||||||
import cn.dev33.satoken.sso.function.NotLoginViewFunction;
|
import cn.dev33.satoken.sso.function.NotLoginViewFunction;
|
||||||
import cn.dev33.satoken.sso.function.SendHttpFunction;
|
import cn.dev33.satoken.sso.function.SendRequestFunction;
|
||||||
import cn.dev33.satoken.util.SaResult;
|
import cn.dev33.satoken.util.SaResult;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -36,10 +37,19 @@ public class SaSsoServerStrategy {
|
|||||||
/**
|
/**
|
||||||
* 发送 Http 请求的处理函数
|
* 发送 Http 请求的处理函数
|
||||||
*/
|
*/
|
||||||
public SendHttpFunction sendHttp = url -> {
|
public SendRequestFunction sendRequest = url -> {
|
||||||
return SaManager.getSaHttpTemplate().get(url);
|
return SaManager.getSaHttpTemplate().get(url);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用异步模式执行一个任务
|
||||||
|
*/
|
||||||
|
public SaParamFunction<SaFunction> asyncRun = fun -> {
|
||||||
|
new Thread(() -> {
|
||||||
|
fun.run();
|
||||||
|
}).start();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 未登录时返回的 View
|
* 未登录时返回的 View
|
||||||
*/
|
*/
|
||||||
@ -75,7 +85,7 @@ public class SaSsoServerStrategy {
|
|||||||
* @return 返回的结果
|
* @return 返回的结果
|
||||||
*/
|
*/
|
||||||
public SaResult requestAsSaResult(String url) {
|
public SaResult requestAsSaResult(String url) {
|
||||||
String body = sendHttp.apply(url);
|
String body = sendRequest.apply(url);
|
||||||
Map<String, Object> map = SaManager.getSaJsonTemplate().jsonToMap(body);
|
Map<String, Object> map = SaManager.getSaJsonTemplate().jsonToMap(body);
|
||||||
return new SaResult(map);
|
return new SaResult(map);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -213,7 +213,6 @@ public class SaSsoClientTemplate extends SaSsoTemplate {
|
|||||||
* @return 单点注销URL
|
* @return 单点注销URL
|
||||||
*/
|
*/
|
||||||
public SaSsoMessage buildSloMessage(Object loginId, SaLogoutParameter logoutParameter) {
|
public SaSsoMessage buildSloMessage(Object loginId, SaLogoutParameter logoutParameter) {
|
||||||
SaSsoClientConfig ssoConfig = getClientConfig();
|
|
||||||
SaSsoMessage message = new SaSsoMessage();
|
SaSsoMessage message = new SaSsoMessage();
|
||||||
message.setType(SaSsoConsts.MESSAGE_SIGNOUT);
|
message.setType(SaSsoConsts.MESSAGE_SIGNOUT);
|
||||||
message.set(paramName.client, getClient());
|
message.set(paramName.client, getClient());
|
||||||
|
|||||||
@ -507,7 +507,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SaSession session = getStpLogic().getSessionByLoginId(loginId);
|
SaSession session = getStpLogicOrGlobal().getSessionByLoginId(loginId);
|
||||||
|
|
||||||
// 取出原来的
|
// 取出原来的
|
||||||
List<SaSsoClientInfo> scmList = session.get(SaSsoConsts.SSO_CLIENT_MODEL_LIST_KEY_, ArrayList::new);
|
List<SaSsoClientInfo> scmList = session.get(SaSsoConsts.SSO_CLIENT_MODEL_LIST_KEY_, ArrayList::new);
|
||||||
@ -522,7 +522,9 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
if(scmList.size() > maxRegClient) {
|
if(scmList.size() > maxRegClient) {
|
||||||
SaSsoClientInfo removeScm = scmList.remove(0);
|
SaSsoClientInfo removeScm = scmList.remove(0);
|
||||||
notifyClientLogout(loginId, null, removeScm, true, true);
|
strategy.asyncRun.run(() -> {
|
||||||
|
notifyClientLogout(loginId, null, removeScm, true, true);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -562,7 +564,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
|||||||
* @param loginId 指定账号
|
* @param loginId 指定账号
|
||||||
*/
|
*/
|
||||||
public void ssoLogout(Object loginId) {
|
public void ssoLogout(Object loginId) {
|
||||||
ssoLogout(loginId, getStpLogic().createSaLogoutParameter());
|
ssoLogout(loginId, getStpLogicOrGlobal().createSaLogoutParameter());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -577,32 +579,37 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
|||||||
pushToAllClientByLogoutCall(loginId, logoutParameter);
|
pushToAllClientByLogoutCall(loginId, logoutParameter);
|
||||||
|
|
||||||
// 2、SaSession 挂载的 Client 端注销会话
|
// 2、SaSession 挂载的 Client 端注销会话
|
||||||
SaSession session = getStpLogic().getSessionByLoginId(loginId, false);
|
SaSession session = getStpLogicOrGlobal().getSessionByLoginId(loginId, false);
|
||||||
if(session == null) {
|
if(session == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<SaSsoClientInfo> scmList = session.get(SaSsoConsts.SSO_CLIENT_MODEL_LIST_KEY_, ArrayList::new);
|
List<SaSsoClientInfo> scmList = session.get(SaSsoConsts.SSO_CLIENT_MODEL_LIST_KEY_, ArrayList::new);
|
||||||
scmList.forEach(scm -> {
|
scmList.forEach(scm -> {
|
||||||
notifyClientLogout(loginId, logoutParameter.getDeviceId(), scm, false, false);
|
strategy.asyncRun.run(() -> {
|
||||||
|
notifyClientLogout(loginId, logoutParameter.getDeviceId(), scm, false, false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3、Server 端本身注销
|
// 3、Server 端本身注销
|
||||||
getStpLogic().logout(loginId, logoutParameter);
|
getStpLogicOrGlobal().logout(loginId, logoutParameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通知指定账号的指定客户端注销
|
* 通知指定账号的指定客户端注销
|
||||||
|
*
|
||||||
* @param loginId 指定账号
|
* @param loginId 指定账号
|
||||||
* @param deviceId 指定设备 id
|
* @param deviceId 指定设备 id
|
||||||
* @param scm 客户端信息对象
|
* @param scm 客户端信息对象
|
||||||
* @param autoLogout 是否为超过 maxRegClient 的自动注销
|
* @param autoLogout 是否为超过 maxRegClient 的自动注销
|
||||||
* @param isPushWork 如果该 client 没有注册注销回调地址,是否使用 push 消息的方式进行注销回调通知
|
* @param isPushWork 如果该 client 没有注册注销回调地址,是否使用 push 消息的方式进行注销回调通知
|
||||||
|
*
|
||||||
|
* @return /
|
||||||
*/
|
*/
|
||||||
public void notifyClientLogout(Object loginId, String deviceId, SaSsoClientInfo scm, boolean autoLogout, boolean isPushWork) {
|
public String notifyClientLogout(Object loginId, String deviceId, SaSsoClientInfo scm, boolean autoLogout, boolean isPushWork) {
|
||||||
|
|
||||||
// 如果给个null值,不进行任何操作
|
// 如果给个null值,不进行任何操作
|
||||||
if(scm == null || scm.mode != SaSsoConsts.SSO_MODE_3) {
|
if(scm == null || scm.mode != SaSsoConsts.SSO_MODE_3) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果此 Client 并没有注册 单点注销 回调地址
|
// 如果此 Client 并没有注册 单点注销 回调地址
|
||||||
@ -610,9 +617,10 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
|||||||
if(SaFoxUtil.isEmpty(sloCallUrl)) {
|
if(SaFoxUtil.isEmpty(sloCallUrl)) {
|
||||||
// TODO 代码有效性待验证
|
// TODO 代码有效性待验证
|
||||||
if(isPushWork && SaFoxUtil.isNotEmpty(scm.getClient())) {
|
if(isPushWork && SaFoxUtil.isNotEmpty(scm.getClient())) {
|
||||||
pushToClientByLogoutCall(getClient(scm.getClient()), loginId, getStpLogic().createSaLogoutParameter());
|
SaSsoClientModel client = getClient(scm.getClient());
|
||||||
|
return pushToClientByLogoutCall(client, loginId, getStpLogicOrGlobal().createSaLogoutParameter());
|
||||||
}
|
}
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 参数
|
// 参数
|
||||||
@ -627,7 +635,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
|||||||
String finalUrl = SaFoxUtil.joinParam(sloCallUrl, signParamsStr);
|
String finalUrl = SaFoxUtil.joinParam(sloCallUrl, signParamsStr);
|
||||||
|
|
||||||
// 发起请求
|
// 发起请求
|
||||||
strategy.sendHttp.apply(finalUrl);
|
return strategy.sendRequest.apply(finalUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -644,7 +652,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
|||||||
String noticeUrl = clientModel.splicingPushUrl();
|
String noticeUrl = clientModel.splicingPushUrl();
|
||||||
String paramsStr = getSignTemplate(clientModel.getClient()).addSignParamsAndJoin(message);
|
String paramsStr = getSignTemplate(clientModel.getClient()).addSignParamsAndJoin(message);
|
||||||
String finalUrl = SaFoxUtil.joinParam(noticeUrl, paramsStr);
|
String finalUrl = SaFoxUtil.joinParam(noticeUrl, paramsStr);
|
||||||
return strategy.sendHttp.apply(finalUrl);
|
return strategy.sendRequest.apply(finalUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -691,7 +699,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
|||||||
public void pushToAllClient(SaSsoMessage message) {
|
public void pushToAllClient(SaSsoMessage message) {
|
||||||
List<SaSsoClientModel> needPushClients = getNeedPushClients();
|
List<SaSsoClientModel> needPushClients = getNeedPushClients();
|
||||||
for (SaSsoClientModel client : needPushClients) {
|
for (SaSsoClientModel client : needPushClients) {
|
||||||
pushMessage(client, message);
|
strategy.asyncRun.run(() -> pushMessage(client, message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -705,7 +713,9 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
|||||||
List<SaSsoClientModel> npClients = getNeedPushClients();
|
List<SaSsoClientModel> npClients = getNeedPushClients();
|
||||||
for (SaSsoClientModel client : npClients) {
|
for (SaSsoClientModel client : npClients) {
|
||||||
if(client.getIsSlo()) {
|
if(client.getIsSlo()) {
|
||||||
pushToClientByLogoutCall(client, loginId, logoutParameter);
|
strategy.asyncRun.run(() -> {
|
||||||
|
pushToClientByLogoutCall(client, loginId, logoutParameter);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -715,13 +725,14 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
|||||||
*
|
*
|
||||||
* @param loginId /
|
* @param loginId /
|
||||||
* @param logoutParameter 注销参数
|
* @param logoutParameter 注销参数
|
||||||
|
* @return /
|
||||||
*/
|
*/
|
||||||
public void pushToClientByLogoutCall(SaSsoClientModel client, Object loginId, SaLogoutParameter logoutParameter) {
|
public String pushToClientByLogoutCall(SaSsoClientModel client, Object loginId, SaLogoutParameter logoutParameter) {
|
||||||
SaSsoMessage message = new SaSsoMessage();
|
SaSsoMessage message = new SaSsoMessage();
|
||||||
message.setType(SaSsoConsts.MESSAGE_LOGOUT_CALL);
|
message.setType(SaSsoConsts.MESSAGE_LOGOUT_CALL);
|
||||||
message.set(paramName.loginId, loginId);
|
message.set(paramName.loginId, loginId);
|
||||||
message.set(paramName.deviceId, logoutParameter.getDeviceId());
|
message.set(paramName.deviceId, logoutParameter.getDeviceId());
|
||||||
pushMessage(client, message);
|
return pushMessage(client, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -766,7 +777,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
|||||||
* @return key
|
* @return key
|
||||||
*/
|
*/
|
||||||
public String splicingTicketModelSaveKey(String ticket) {
|
public String splicingTicketModelSaveKey(String ticket) {
|
||||||
return getStpLogic().getConfigOrGlobal().getTokenName() + ":ticket:" + ticket;
|
return getStpLogicOrGlobal().getConfigOrGlobal().getTokenName() + ":ticket:" + ticket;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -780,7 +791,7 @@ public class SaSsoServerTemplate extends SaSsoTemplate {
|
|||||||
if(SaFoxUtil.isEmpty(client) || SaSsoConsts.CLIENT_WILDCARD.equals(client)) {
|
if(SaFoxUtil.isEmpty(client) || SaSsoConsts.CLIENT_WILDCARD.equals(client)) {
|
||||||
client = SaSsoConsts.CLIENT_ANON;
|
client = SaSsoConsts.CLIENT_ANON;
|
||||||
}
|
}
|
||||||
return getStpLogic().getConfigOrGlobal().getTokenName() + ":ticket-index:" + client + ":" + id;
|
return getStpLogicOrGlobal().getConfigOrGlobal().getTokenName() + ":ticket-index:" + client + ":" + id;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,11 +61,39 @@ public class SaSsoTemplate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取底层使用的会话对象
|
* 底层使用的 StpLogic 对象
|
||||||
|
*/
|
||||||
|
StpLogic stpLogic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入底层使用的会话对象
|
||||||
|
*
|
||||||
|
* @param stpLogic /
|
||||||
|
* @return /
|
||||||
|
*/
|
||||||
|
public SaSsoTemplate setStpLogic(StpLogic stpLogic) {
|
||||||
|
this.stpLogic = stpLogic;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取底层使用的会话对象
|
||||||
* @return /
|
* @return /
|
||||||
*/
|
*/
|
||||||
public StpLogic getStpLogic() {
|
public StpLogic getStpLogic() {
|
||||||
return StpUtil.stpLogic;
|
return this.stpLogic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取底层使用的会话对象,如果没有配置则返回全局默认 StpLogic
|
||||||
|
* @return /
|
||||||
|
*/
|
||||||
|
public StpLogic getStpLogicOrGlobal() {
|
||||||
|
StpLogic stpLogic = getStpLogic();
|
||||||
|
if (stpLogic == null) {
|
||||||
|
return StpUtil.stpLogic;
|
||||||
|
}
|
||||||
|
return stpLogic;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------- 消息处理
|
// ----------- 消息处理
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user