fix: SSO登录退出相关问题

This commit is contained in:
CaptainB 2022-10-20 18:35:36 +08:00 committed by 刘瑞斌
parent 7b0284f38f
commit 14c2d2dd81
7 changed files with 94 additions and 28 deletions

View File

@ -9,6 +9,7 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.reactive.result.view.Rendering;
import org.springframework.web.server.WebSession;
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
import java.util.Locale;
@ -23,7 +24,7 @@ public class SSOController {
@MsAuditLog(module = OperLogModule.AUTH_TITLE, type = OperLogConstants.LOGIN, title = "登录")
public Rendering callbackWithAuthId(@RequestParam("code") String code, @PathVariable("authId") String authId, WebSession session, Locale locale) throws Exception {
ssoService.exchangeToken(code, authId, session, locale);
return Rendering.redirectTo("/?_token=" + CodingUtil.base64Encoding(session.getId()))
return Rendering.redirectTo("/#/?_token=" + CodingUtil.base64Encoding(session.getId()))
.build();
}
@ -31,7 +32,7 @@ public class SSOController {
@MsAuditLog(module = OperLogModule.AUTH_TITLE, type = OperLogConstants.LOGIN, title = "登录")
public Rendering callback(@RequestParam("code") String code, @RequestParam("state") String authId, WebSession session, Locale locale) throws Exception {
ssoService.exchangeToken(code, authId, session, locale);
return Rendering.redirectTo("/?_token=" + CodingUtil.base64Encoding(session.getId()))
return Rendering.redirectTo("/#/?_token=" + CodingUtil.base64Encoding(session.getId()))
.build();
}
@ -39,28 +40,26 @@ public class SSOController {
@MsAuditLog(module = OperLogModule.AUTH_TITLE, type = OperLogConstants.LOGIN, title = "登录")
public Rendering casCallback(@RequestParam("ticket") String ticket, @PathVariable("authId") String authId, WebSession session, Locale locale) throws Exception {
ssoService.serviceValidate(ticket, authId, session, locale);
return Rendering.redirectTo("/?_token=" + CodingUtil.base64Encoding(session.getId()))
return Rendering.redirectTo("/#/?_token=" + CodingUtil.base64Encoding(session.getId()))
.build();
}
/**
* oidc 登出 callback
*/
@PostMapping("/callback/logout")
public Rendering logoutCallback(@RequestParam("logout_token") String logoutToken) {
ssoService.kickOutUser(logoutToken);
return Rendering.redirectTo("/#/login")
.build();
}
/**
* cas 登出 callback
*/
@PostMapping("/callback/cas/logout")
public Rendering logoutCasCallback(@RequestParam("logoutRequest") String logoutRequest) {
ssoService.kickOutCasUser(logoutRequest);
return Rendering.redirectTo("/#/login")
.build();
}
// /**
// * oidc 登出 callback
// */
// @PostMapping("/callback/logout")
// public Mono<Void> logoutCallback(@RequestParam("logout_token") String logoutToken) {
// ssoService.kickOutUser(logoutToken);
// return Mono.empty();
// }
//
// /**
// * cas 登出 callback
// */
// @PostMapping("/callback/cas/logout")
// public Mono<Void> logoutCasCallback(@RequestParam("logoutRequest") String logoutRequest) {
// ssoService.kickOutCasUser(logoutRequest);
// return Mono.empty();
// }
}

View File

@ -18,7 +18,7 @@ import java.util.Optional;
public class SessionFilter implements WebFilter {
// 所有模块的前缀
private static final String[] PREFIX = new String[]{"/setting", "/project", "/api", "/performance", "/track", "/workstation", "/ui", "/report"};
private static final String[] TO_SUB_SERVICE = new String[]{"/license", "/system", "/resource"};
private static final String[] TO_SUB_SERVICE = new String[]{"/license", "/system", "/resource", "/sso/callback/logout", "/sso/callback/cas/logout"};
private static final String PERFORMANCE_DOWNLOAD_PREFIX = "/jmeter/";
private static final String API_DOWNLOAD_PREFIX = "/api/jmeter/";

View File

@ -189,6 +189,7 @@ export default {
activated() {
this.initTableData();
this.$router.replace({query: null})
},
methods: {
currentUser: () => {

View File

@ -1,5 +1,6 @@
import Vue from 'vue';
import VueI18n from "vue-i18n";
Vue.use(VueI18n);
// 直接加载翻译的语言文件
@ -45,9 +46,10 @@ const setLang = lang => {
}
export const setLanguage = lang => {
if (lang) {
lang = lang.replace('_', '-');
if (!lang) {
return;
}
lang = lang.replace('_', '-');
if (i18n.locale !== lang) {
importLanguage(lang).then(setLang);
} else {

View File

@ -39,9 +39,8 @@ instance.interceptors.request.use(
}
// sso callback 过来的会有sessionId在url上
if (!config.headers['X-AUTH-TOKEN']) {
const paramsStr = window.location.search
const params = new URLSearchParams(paramsStr)
let sessionId = params.get('_token');
const paramsStr = window.location.href
let sessionId = paramsStr.split('_token=')[1]
if (sessionId) {
config.headers['X-AUTH-TOKEN'] = Base64.decode(sessionId);
}

View File

@ -0,0 +1,33 @@
package io.metersphere.controller;
import io.metersphere.service.SSOLogoutService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("sso")
public class SSOLogoutController {
@Resource
private SSOLogoutService ssoLogoutService;
/**
* oidc 登出 callback
*/
@PostMapping("/callback/logout")
public void logoutCallback(@RequestParam("logout_token") String logoutToken) {
ssoLogoutService.kickOutUser(logoutToken);
}
/**
* cas 登出 callback
*/
@PostMapping("/callback/cas/logout")
public void logoutCasCallback(@RequestParam("logoutRequest") String logoutRequest) {
ssoLogoutService.kickOutCasUser(logoutRequest);
}
}

View File

@ -3,9 +3,12 @@ package io.metersphere.service;
import io.metersphere.base.domain.AuthSource;
import io.metersphere.base.mapper.AuthSourceMapper;
import io.metersphere.commons.constants.UserSource;
import io.metersphere.commons.utils.CodingUtil;
import io.metersphere.commons.utils.JSON;
import io.metersphere.commons.utils.SessionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@ -18,6 +21,8 @@ public class SSOLogoutService {
private AuthSourceMapper authSourceMapper;
@Resource
private RestTemplate restTemplate;
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* oidc logout
@ -35,4 +40,31 @@ public class SSOLogoutService {
}
}
}
public void kickOutUser(String logoutToken) {
String[] split = StringUtils.split(logoutToken, '.');
for (String s : split) {
String v = CodingUtil.base64Decoding(s);
Map obj = JSON.parseMap(v);
String sub = (String) obj.get("sub");
if (StringUtils.isNotEmpty(sub)) {
SessionUtils.kickOutUser(sub);
break;
}
}
}
public void kickOutCasUser(String logoutRequest) {
String ticket = StringUtils.substringBetween(logoutRequest, "<samlp:SessionIndex>", "</samlp:SessionIndex>");
if (StringUtils.isEmpty(ticket)) {
return;
}
String name = stringRedisTemplate.opsForValue().get(ticket);
if (StringUtils.isEmpty(name)) {
return;
}
SessionUtils.kickOutUser(name);
stringRedisTemplate.delete(ticket);
}
}