mirror of
https://gitee.com/dromara/sa-token.git
synced 2025-10-07 15:14:23 +08:00
refactor: 略微优化 sso 相关 demo
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
// 服务器接口主机地址
|
||||
var baseUrl = "http://sa-sso-client1.com:9003";
|
||||
|
||||
// 封装一下Ajax
|
||||
function ajax(path, data, successFn, errorFn) {
|
||||
console.log('发起请求:', baseUrl + path, JSON.stringify(data));
|
||||
fetch(baseUrl + path, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'satoken': localStorage.getItem('satoken')
|
||||
},
|
||||
body: serializeToQueryString(data),
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(res => {
|
||||
console.log('返回数据:', res);
|
||||
if(res.code === 500) {
|
||||
return alert(res.msg);
|
||||
}
|
||||
successFn(res);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('请求失败:', error);
|
||||
return alert("异常:" + JSON.stringify(error));
|
||||
});
|
||||
}
|
||||
|
||||
// ------------ 工具方法 ---------------
|
||||
|
||||
// 从url中查询到指定名称的参数值
|
||||
function getParam(name, defaultValue) {
|
||||
var query = window.location.search.substring(1);
|
||||
var vars = query.split("&");
|
||||
for (var i = 0; i < vars.length; i++) {
|
||||
var pair = vars[i].split("=");
|
||||
if (pair[0] == name) {
|
||||
return pair[1];
|
||||
}
|
||||
}
|
||||
return (defaultValue == undefined ? null : defaultValue);
|
||||
}
|
||||
|
||||
// 将 json 对象序列化为kv字符串,形如:name=Joh&age=30&active=true
|
||||
function serializeToQueryString(obj) {
|
||||
return Object.entries(obj)
|
||||
.filter(([_, value]) => value != null) // 过滤 null 和 undefined
|
||||
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
|
||||
.join('&');
|
||||
}
|
||||
|
||||
// 向指定标签里 set 内容
|
||||
function setHtml(select, html) {
|
||||
const dom = document.querySelector('.is-login');
|
||||
if(dom) {
|
||||
dom.innerHTML = html;
|
||||
}
|
||||
}
|
@@ -8,31 +8,18 @@
|
||||
<h2>Sa-Token SSO-Client 应用端(前后端分离版-原生h5)</h2>
|
||||
<p>当前是否登录:<b class="is-login"></b></p>
|
||||
<p>
|
||||
<a href="javascript:location.href='sso-login.html?back=' + encodeURIComponent(location.href);">登录</a>
|
||||
<a href="javascript:location.href=baseUrl + '/sso/logout?satoken=' + localStorage.satoken + '&back=' + encodeURIComponent(location.href);">注销</a>
|
||||
<a class="login-btn">登录</a>
|
||||
<a class="logout-btn">注销</a>
|
||||
</p>
|
||||
<script src="https://unpkg.zhimg.com/jquery@3.4.1/dist/jquery.min.js"></script>
|
||||
<script src="common.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
// 后端接口地址
|
||||
var baseUrl = "http://sa-sso-client1.com:9002";
|
||||
|
||||
// 查询当前会话是否登录
|
||||
$.ajax({
|
||||
url: baseUrl + '/sso/isLogin',
|
||||
type: "post",
|
||||
dataType: 'json',
|
||||
headers: {
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
"satoken": localStorage.getItem("satoken")
|
||||
},
|
||||
success: function(res){
|
||||
$('.is-login').html(res.data + '');
|
||||
},
|
||||
error: function(xhr, type, errorThrown){
|
||||
return alert("异常:" + JSON.stringify(xhr));
|
||||
}
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
ajax('/sso/isLogin', {}, function(res){
|
||||
setHtml('.is-login', res.data);
|
||||
})
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
@@ -11,83 +11,35 @@
|
||||
<div class="login-box">
|
||||
|
||||
</div>
|
||||
<script src="https://unpkg.zhimg.com/jquery@3.4.1/dist/jquery.min.js"></script>
|
||||
<script>window.jQuery || alert('当前页面CDN服务商已宕机,请将所有js包更换为本地依赖')</script>
|
||||
<script src="common.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
// 后端接口地址
|
||||
var baseUrl = "http://sa-sso-client1.com:9002";
|
||||
|
||||
var back = getParam('back', '/');
|
||||
var ticket = getParam('ticket');
|
||||
$(function() {
|
||||
|
||||
window.onload = function(){
|
||||
if(ticket) {
|
||||
doLoginByTicket(ticket);
|
||||
} else {
|
||||
goSsoAuthUrl();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 重定向至认证中心
|
||||
function goSsoAuthUrl() {
|
||||
sa.ajax('/sso/getSsoAuthUrl', {clientLoginUrl: location.href}, function(res) {
|
||||
console.log(res);
|
||||
ajax('/sso/getSsoAuthUrl', {clientLoginUrl: location.href}, function(res) {
|
||||
location.href = res.data;
|
||||
})
|
||||
}
|
||||
|
||||
// 根据ticket值登录
|
||||
function doLoginByTicket(ticket) {
|
||||
sa.ajax('/sso/doLoginByTicket', {ticket: ticket}, function(res) {
|
||||
console.log(res);
|
||||
if(res.code == 200) {
|
||||
localStorage.setItem('satoken', res.data);
|
||||
location.href = decodeURIComponent(back);
|
||||
} else {
|
||||
alert(res.msg);
|
||||
}
|
||||
ajax('/sso/doLoginByTicket', {ticket: ticket}, function(res) {
|
||||
localStorage.setItem('satoken', res.data);
|
||||
location.href = decodeURIComponent(back);
|
||||
})
|
||||
}
|
||||
|
||||
// 从url中查询到指定名称的参数值
|
||||
function getParam(name, defaultValue){
|
||||
var query = window.location.search.substring(1);
|
||||
var vars = query.split("&");
|
||||
for (var i=0;i<vars.length;i++) {
|
||||
var pair = vars[i].split("=");
|
||||
if(pair[0] == name){return pair[1];}
|
||||
}
|
||||
return(defaultValue == undefined ? null : defaultValue);
|
||||
}
|
||||
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
var sa = {};
|
||||
|
||||
// 封装一下Ajax
|
||||
sa.ajax = function(url, data, successFn) {
|
||||
// sa.loading("正在努力加载...");
|
||||
$.ajax({
|
||||
url: baseUrl + url,
|
||||
type: "post",
|
||||
data: data,
|
||||
dataType: 'json',
|
||||
headers: {
|
||||
satoken: localStorage.getItem('satoken')
|
||||
},
|
||||
success: function(res){
|
||||
console.log('返回数据:', res);
|
||||
successFn(res);
|
||||
},
|
||||
error: function(xhr, type, errorThrown){
|
||||
if(xhr.status == 0){
|
||||
return alert('无法连接到服务器,请检查网络');
|
||||
}
|
||||
return alert("异常:" + JSON.stringify(xhr));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -4,6 +4,7 @@ import cn.dev33.satoken.sso.model.SaCheckTicketResult;
|
||||
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
|
||||
import cn.dev33.satoken.sso.template.SaSsoUtil;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -35,7 +36,10 @@ public class H5Controller {
|
||||
@RequestMapping("/sso/doLoginByTicket")
|
||||
public SaResult doLoginByTicket(String ticket) {
|
||||
SaCheckTicketResult ctr = SaSsoClientProcessor.instance.checkTicket(ticket, "/sso/doLoginByTicket");
|
||||
StpUtil.login(ctr.loginId, ctr.remainSessionTimeout);
|
||||
StpUtil.login(ctr.loginId, new SaLoginParameter()
|
||||
.setTimeout(ctr.remainTokenTimeout)
|
||||
.setDeviceId(ctr.deviceId)
|
||||
);
|
||||
return SaResult.data(StpUtil.getTokenValue());
|
||||
}
|
||||
|
||||
|
@@ -1,13 +1,10 @@
|
||||
package com.pj.h5;
|
||||
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.filter.SaServletFilter;
|
||||
import cn.dev33.satoken.fun.strategy.SaCorsHandleFunction;
|
||||
import cn.dev33.satoken.router.SaHttpMethod;
|
||||
import cn.dev33.satoken.router.SaRouter;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* [Sa-Token 权限认证] 配置类 (解决跨域问题)
|
||||
@@ -15,50 +12,29 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
* @author click33
|
||||
*/
|
||||
@Configuration
|
||||
public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
public class SaTokenConfigure {
|
||||
|
||||
/**
|
||||
* 注册 [Sa-Token 全局过滤器]
|
||||
* CORS 跨域处理策略
|
||||
*/
|
||||
@Bean
|
||||
public SaServletFilter getSaServletFilter() {
|
||||
return new SaServletFilter()
|
||||
public SaCorsHandleFunction corsHandle() {
|
||||
return (req, res, sto) -> {
|
||||
res.
|
||||
// 允许指定域访问跨域资源
|
||||
setHeader("Access-Control-Allow-Origin", "*")
|
||||
// 允许所有请求方式
|
||||
.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
|
||||
// 有效时间
|
||||
.setHeader("Access-Control-Max-Age", "3600")
|
||||
// 允许的header参数
|
||||
.setHeader("Access-Control-Allow-Headers", "*");
|
||||
|
||||
// 指定 [拦截路由] 与 [放行路由]
|
||||
.addInclude("/**").addExclude("/favicon.ico")
|
||||
|
||||
// 认证函数: 每次请求执行
|
||||
.setAuth(obj -> {
|
||||
// SaManager.getLog().debug("----- 请求path={} 提交token={}", SaHolder.getRequest().getRequestPath(), StpUtil.getTokenValue());
|
||||
// ...
|
||||
})
|
||||
|
||||
// 异常处理函数:每次认证函数发生异常时执行此函数
|
||||
.setError(e -> {
|
||||
return SaResult.error(e.getMessage());
|
||||
})
|
||||
|
||||
// 前置函数:在每次认证函数之前执行
|
||||
.setBeforeAuth(obj -> {
|
||||
SaHolder.getResponse()
|
||||
|
||||
// ---------- 设置跨域响应头 ----------
|
||||
// 允许指定域访问跨域资源
|
||||
.setHeader("Access-Control-Allow-Origin", "*")
|
||||
// 允许所有请求方式
|
||||
.setHeader("Access-Control-Allow-Methods", "*")
|
||||
// 允许的header参数
|
||||
.setHeader("Access-Control-Allow-Headers", "*")
|
||||
// 有效时间
|
||||
.setHeader("Access-Control-Max-Age", "3600")
|
||||
;
|
||||
|
||||
// 如果是预检请求,则立即返回到前端
|
||||
SaRouter.match(SaHttpMethod.OPTIONS)
|
||||
.free(r -> System.out.println("--------OPTIONS预检请求,不做处理"))
|
||||
.back();
|
||||
})
|
||||
;
|
||||
// 如果是预检请求,则立即返回到前端
|
||||
SaRouter.match(SaHttpMethod.OPTIONS)
|
||||
.free(r -> System.out.println("--------OPTIONS预检请求,不做处理"))
|
||||
.back();
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,53 @@
|
||||
package com.pj.h5;
|
||||
|
||||
import cn.dev33.satoken.sso.model.SaCheckTicketResult;
|
||||
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
|
||||
import cn.dev33.satoken.sso.template.SaSsoUtil;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
||||
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.RestController;
|
||||
|
||||
/**
|
||||
* 前后台分离架构下集成SSO所需的代码 (SSO-Client端)
|
||||
* <p>(注:如果不需要前后端分离架构下集成SSO,可删除此包下所有代码)</p>
|
||||
* @author click33
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
public class H5Controller {
|
||||
|
||||
// 当前是否登录
|
||||
@RequestMapping("/sso/isLogin")
|
||||
public Object isLogin() {
|
||||
return SaResult.data(StpUtil.isLogin());
|
||||
}
|
||||
|
||||
// 返回SSO认证中心登录地址
|
||||
@RequestMapping("/sso/getSsoAuthUrl")
|
||||
public SaResult getSsoAuthUrl(String clientLoginUrl) {
|
||||
String serverAuthUrl = SaSsoUtil.buildServerAuthUrl(clientLoginUrl, "");
|
||||
return SaResult.data(serverAuthUrl);
|
||||
}
|
||||
|
||||
// 根据ticket进行登录
|
||||
@RequestMapping("/sso/doLoginByTicket")
|
||||
public SaResult doLoginByTicket(String ticket) {
|
||||
SaCheckTicketResult ctr = SaSsoClientProcessor.instance.checkTicket(ticket, "/sso/doLoginByTicket");
|
||||
StpUtil.login(ctr.loginId, new SaLoginParameter()
|
||||
.setTimeout(ctr.remainTokenTimeout)
|
||||
.setDeviceId(ctr.deviceId)
|
||||
);
|
||||
return SaResult.data(StpUtil.getTokenValue());
|
||||
}
|
||||
|
||||
// 全局异常拦截
|
||||
@ExceptionHandler
|
||||
public SaResult handlerException(Exception e) {
|
||||
e.printStackTrace();
|
||||
return SaResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
package com.pj.h5;
|
||||
|
||||
import cn.dev33.satoken.fun.strategy.SaCorsHandleFunction;
|
||||
import cn.dev33.satoken.router.SaHttpMethod;
|
||||
import cn.dev33.satoken.router.SaRouter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* [Sa-Token 权限认证] 配置类 (解决跨域问题)
|
||||
*
|
||||
* @author click33
|
||||
*/
|
||||
@Configuration
|
||||
public class SaTokenConfigure {
|
||||
|
||||
/**
|
||||
* CORS 跨域处理策略
|
||||
*/
|
||||
@Bean
|
||||
public SaCorsHandleFunction corsHandle() {
|
||||
return (req, res, sto) -> {
|
||||
res.
|
||||
// 允许指定域访问跨域资源
|
||||
setHeader("Access-Control-Allow-Origin", "*")
|
||||
// 允许所有请求方式
|
||||
.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
|
||||
// 有效时间
|
||||
.setHeader("Access-Control-Max-Age", "3600")
|
||||
// 允许的header参数
|
||||
.setHeader("Access-Control-Allow-Headers", "*");
|
||||
|
||||
// 如果是预检请求,则立即返回到前端
|
||||
SaRouter.match(SaHttpMethod.OPTIONS)
|
||||
.free(r -> System.out.println("--------OPTIONS预检请求,不做处理"))
|
||||
.back();
|
||||
};
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user