fix: SSO登录退出相关问题
This commit is contained in:
parent
7b0284f38f
commit
14c2d2dd81
|
@ -9,6 +9,7 @@ import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.reactive.result.view.Rendering;
|
import org.springframework.web.reactive.result.view.Rendering;
|
||||||
import org.springframework.web.server.WebSession;
|
import org.springframework.web.server.WebSession;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -23,7 +24,7 @@ public class SSOController {
|
||||||
@MsAuditLog(module = OperLogModule.AUTH_TITLE, type = OperLogConstants.LOGIN, title = "登录")
|
@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 {
|
public Rendering callbackWithAuthId(@RequestParam("code") String code, @PathVariable("authId") String authId, WebSession session, Locale locale) throws Exception {
|
||||||
ssoService.exchangeToken(code, authId, session, locale);
|
ssoService.exchangeToken(code, authId, session, locale);
|
||||||
return Rendering.redirectTo("/?_token=" + CodingUtil.base64Encoding(session.getId()))
|
return Rendering.redirectTo("/#/?_token=" + CodingUtil.base64Encoding(session.getId()))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ public class SSOController {
|
||||||
@MsAuditLog(module = OperLogModule.AUTH_TITLE, type = OperLogConstants.LOGIN, title = "登录")
|
@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 {
|
public Rendering callback(@RequestParam("code") String code, @RequestParam("state") String authId, WebSession session, Locale locale) throws Exception {
|
||||||
ssoService.exchangeToken(code, authId, session, locale);
|
ssoService.exchangeToken(code, authId, session, locale);
|
||||||
return Rendering.redirectTo("/?_token=" + CodingUtil.base64Encoding(session.getId()))
|
return Rendering.redirectTo("/#/?_token=" + CodingUtil.base64Encoding(session.getId()))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,28 +40,26 @@ public class SSOController {
|
||||||
@MsAuditLog(module = OperLogModule.AUTH_TITLE, type = OperLogConstants.LOGIN, title = "登录")
|
@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 {
|
public Rendering casCallback(@RequestParam("ticket") String ticket, @PathVariable("authId") String authId, WebSession session, Locale locale) throws Exception {
|
||||||
ssoService.serviceValidate(ticket, authId, session, locale);
|
ssoService.serviceValidate(ticket, authId, session, locale);
|
||||||
return Rendering.redirectTo("/?_token=" + CodingUtil.base64Encoding(session.getId()))
|
return Rendering.redirectTo("/#/?_token=" + CodingUtil.base64Encoding(session.getId()))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* oidc 登出 callback
|
// * oidc 登出 callback
|
||||||
*/
|
// */
|
||||||
@PostMapping("/callback/logout")
|
// @PostMapping("/callback/logout")
|
||||||
public Rendering logoutCallback(@RequestParam("logout_token") String logoutToken) {
|
// public Mono<Void> logoutCallback(@RequestParam("logout_token") String logoutToken) {
|
||||||
ssoService.kickOutUser(logoutToken);
|
// ssoService.kickOutUser(logoutToken);
|
||||||
return Rendering.redirectTo("/#/login")
|
// return Mono.empty();
|
||||||
.build();
|
// }
|
||||||
}
|
//
|
||||||
|
// /**
|
||||||
/**
|
// * cas 登出 callback
|
||||||
* cas 登出 callback
|
// */
|
||||||
*/
|
// @PostMapping("/callback/cas/logout")
|
||||||
@PostMapping("/callback/cas/logout")
|
// public Mono<Void> logoutCasCallback(@RequestParam("logoutRequest") String logoutRequest) {
|
||||||
public Rendering logoutCasCallback(@RequestParam("logoutRequest") String logoutRequest) {
|
// ssoService.kickOutCasUser(logoutRequest);
|
||||||
ssoService.kickOutCasUser(logoutRequest);
|
// return Mono.empty();
|
||||||
return Rendering.redirectTo("/#/login")
|
// }
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import java.util.Optional;
|
||||||
public class SessionFilter implements WebFilter {
|
public class SessionFilter implements WebFilter {
|
||||||
// 所有模块的前缀
|
// 所有模块的前缀
|
||||||
private static final String[] PREFIX = new String[]{"/setting", "/project", "/api", "/performance", "/track", "/workstation", "/ui", "/report"};
|
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 PERFORMANCE_DOWNLOAD_PREFIX = "/jmeter/";
|
||||||
private static final String API_DOWNLOAD_PREFIX = "/api/jmeter/";
|
private static final String API_DOWNLOAD_PREFIX = "/api/jmeter/";
|
||||||
|
|
||||||
|
|
|
@ -189,6 +189,7 @@ export default {
|
||||||
|
|
||||||
activated() {
|
activated() {
|
||||||
this.initTableData();
|
this.initTableData();
|
||||||
|
this.$router.replace({query: null})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
currentUser: () => {
|
currentUser: () => {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import VueI18n from "vue-i18n";
|
import VueI18n from "vue-i18n";
|
||||||
|
|
||||||
Vue.use(VueI18n);
|
Vue.use(VueI18n);
|
||||||
|
|
||||||
// 直接加载翻译的语言文件
|
// 直接加载翻译的语言文件
|
||||||
|
@ -45,9 +46,10 @@ const setLang = lang => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const setLanguage = lang => {
|
export const setLanguage = lang => {
|
||||||
if (lang) {
|
if (!lang) {
|
||||||
lang = lang.replace('_', '-');
|
return;
|
||||||
}
|
}
|
||||||
|
lang = lang.replace('_', '-');
|
||||||
if (i18n.locale !== lang) {
|
if (i18n.locale !== lang) {
|
||||||
importLanguage(lang).then(setLang);
|
importLanguage(lang).then(setLang);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -39,9 +39,8 @@ instance.interceptors.request.use(
|
||||||
}
|
}
|
||||||
// sso callback 过来的会有sessionId在url上
|
// sso callback 过来的会有sessionId在url上
|
||||||
if (!config.headers['X-AUTH-TOKEN']) {
|
if (!config.headers['X-AUTH-TOKEN']) {
|
||||||
const paramsStr = window.location.search
|
const paramsStr = window.location.href
|
||||||
const params = new URLSearchParams(paramsStr)
|
let sessionId = paramsStr.split('_token=')[1]
|
||||||
let sessionId = params.get('_token');
|
|
||||||
if (sessionId) {
|
if (sessionId) {
|
||||||
config.headers['X-AUTH-TOKEN'] = Base64.decode(sessionId);
|
config.headers['X-AUTH-TOKEN'] = Base64.decode(sessionId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,9 +3,12 @@ package io.metersphere.service;
|
||||||
import io.metersphere.base.domain.AuthSource;
|
import io.metersphere.base.domain.AuthSource;
|
||||||
import io.metersphere.base.mapper.AuthSourceMapper;
|
import io.metersphere.base.mapper.AuthSourceMapper;
|
||||||
import io.metersphere.commons.constants.UserSource;
|
import io.metersphere.commons.constants.UserSource;
|
||||||
|
import io.metersphere.commons.utils.CodingUtil;
|
||||||
import io.metersphere.commons.utils.JSON;
|
import io.metersphere.commons.utils.JSON;
|
||||||
|
import io.metersphere.commons.utils.SessionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
@ -18,6 +21,8 @@ public class SSOLogoutService {
|
||||||
private AuthSourceMapper authSourceMapper;
|
private AuthSourceMapper authSourceMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private RestTemplate restTemplate;
|
private RestTemplate restTemplate;
|
||||||
|
@Resource
|
||||||
|
private StringRedisTemplate stringRedisTemplate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* oidc logout
|
* 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue