官网地址:Sa-Token
统一认证服务端
直接用的官网的demo,稍加改动,因为要前后端分离,加了一个H5Controller,官网也有详细介绍,这一部分不难,照着做就行了
配置文件:
# Sa-Token 配置
sa-token:
# ------- SSO-模式一相关配置 (非模式一不需要配置)
# cookie:
# 配置 Cookie 作用域
# domain: stp.com
# ------- SSO-模式二相关配置
sso:
# Ticket有效期 (单位: 秒),默认五分钟
ticket-timeout: 300
# 所有允许的授权回调地址
allow-url: "*"
# ------- SSO-模式三相关配置 (下面的配置在使用SSO模式三时打开)
# 是否打开模式三
is-http: true
sign:
# API 接口调用秘钥
secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
# ---- 除了以上配置项,你还需要为 Sa-Token 配置http请求处理器(文档有步骤说明)
业务服务端
因为要用到跨redis,跨域,所以要用到他们的client3模式。
配置文件
sa-token:
# SSO-相关配置
sso:
# SSO-Server端 统一认证地址
auth-url: http://localhost:9000/sso/auth
#auth-url: http://127.0.0.1:5500/sso-login.html
# 使用 Http 请求校验ticket (模式三)
is-http: true
# SSO-Server端 ticket校验地址
check-ticket-url: http://localhost:9000/sso/checkTicket
# 单点注销地址
slo-url: http://localhost:9000/sso/signout
# 查询数据地址
get-data-url: http://localhost:9000/sso/getData
sign:
# API 接口调用秘钥
secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
上面是demo,整合到自己的业务服务端
将自己的token一并返回给前端
@RequestMapping("/sso/doLoginByTicket")
public SaResult doLoginByTicket(String ticket) {
Object loginId = SaSsoProcessor.instance.checkTicket(ticket, "/sso/doLoginByTicket");
if(loginId != null) {
StpUtil.login(loginId);
String token = jwtConfig.createToken(loginId.toString()) ;
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("satoken", StpUtil.getTokenValue());
resultMap.put("token", token);
return SaResult.data(resultMap);
}
return SaResult.error("无效ticket:" + ticket);
}
提供一个api获取登录后的相关信息
@RequestMapping("/loginBySso")
public Result<?> loginBySso(HttpServletRequest request) {
String token = request.getHeader("token");
String userId = jwtConfig.getUsernameFromToken(token);
QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("id", userId);
SysUser sysUser = sysUserService.getOne(queryWrapper, false);
if (sysUser != null) {
if(sysUser.getLockFlag()!=null && sysUser.getLockFlag().equals("1")){
return Result.error("用户已被锁定,请联系管理员解锁!",sysUser);
}
if(!"0".equals(sysUser.getStatus())){
if(DBsUserConstant.Status.SECPERIOD.equals(sysUser.getStatus())){
return Result.error("用户账号已删除,请联系管理员!",sysUser);
}else {
return Result.error("用户账号正在申请中,请联系管理员审核!", sysUser);
}
}
LoginModel model = getUserInfo(sysUser);
return Result.ok(JSON.toJSONString(model));
} else {
return Result.error("无此用户!");
}
}
业务客户端
参考的这个demo
整合到自己的业务客户端
修改路由配置,非常关键
router.beforeEach(async (to, from, next) => {
//debugger;
let token = sessionStorage.getItem('token');
const url = new URL(window.location.href)
const params = getParams(url);
let ticket = params.ticket;
if (ticket && isEmpty(token)) {
//debugger;
//有票据拿token
const ticketRes = await ssoLoginByTicket({ticket: ticket})
sessionStorage.setItem('token', ticketRes.data.data.token)
localStorage.setItem('satoken', ticketRes.data.data.satoken)
const res = await userLoginBySso()
afterLogin(res);
config.configData.sso_enable = true
next({ path: desktopUrl() })
return false
} else {
if (to.path === '/sso') {
config.configData.sso_enable = true
}
//无票据,进入登录页面
if (config.configData.sso_enable && isEmpty(token)) {
const ssoUrlRes = await ssoAuthUrl({clientLoginUrl: location.origin+'/'})
location.href = ssoUrlRes.data.data
return false;
}
//如果直接跳登录页面,不管是不是sso都眺
if (to.path === '/login') {
next()
return false
}
//跳首页时直接决定是登录页还是桌面
if (to.path === '/' || to.path === '/sso') {
if (isEmpty(token)) {
next("login")
} else {
next("desktop")
}
return false
}
//不能反着跳
if (to.path === "/" && from.path === "/login") {
return false;
}
}
next()
})
相关api
import Vue from 'vue'
import {ajax} from '@/utils/httputils'
import config from '@/config/index.js'
const API_URL = config.configData.api_url
const http = (method, url, data) => {
return new Promise((resolve, reject) => {
return ajax(method, url, data).then((res) => {
if (res.data.code == 200) {
resolve(res)
} else {
reject(res)
}
}).catch(error => reject(error))
})
}
/**
* server
* /sso/auth
* /sso/checkTicket
* /sso/signout
* /sso/userinfo
*
* client
* /sso/getSsoAuthUrl
* /sso/doLoginByTicket
* /sso/logout
* /sso/logoutCall
*/
export function ssoAuth(data) {
return http('get', API_URL + "/sso/auth", data)
}
export function ssoCheckTicket(data) {
return http('get', API_URL + "/sso/checkTicket", data)
}
export function ssoSignout(data) {
return http('get', API_URL + "/sso/signout", data)
}
export function ssoUserInfo(data) {
return http('get', API_URL + "/sso/userinfo", data)
}
export function ssoAuthUrl(data) {
return http('get', API_URL + "/sso/getSsoAuthUrl", data)
}
export function ssoLoginByTicket(data) {
return http('get', API_URL + "/sso/doLoginByTicket", data)
}
export function ssoLogout(data) {
return http('get', API_URL + "/sso/logout", data)
}
export function ssoLogoutCall(data) {
return http('get', API_URL + "/sso/logoutCall", data)
}