feat(xPack): CAS 登录
This commit is contained in:
parent
26edcd1e0c
commit
43ae3dd2ce
|
@ -312,24 +312,6 @@
|
|||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- buji-pac4j -->
|
||||
<dependency>
|
||||
<groupId>org.pac4j</groupId>
|
||||
<artifactId>pac4j-cas</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.buji</groupId>
|
||||
<artifactId>buji-pac4j</artifactId>
|
||||
<version>4.0.0</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>shiro-web</artifactId>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
|
|
|
@ -21,7 +21,12 @@ public class ShiroUtils {
|
|||
filterChainDefinitionMap.put("/js/**", "anon");
|
||||
filterChainDefinitionMap.put("/img/**", "anon");
|
||||
filterChainDefinitionMap.put("/fonts/**", "anon");
|
||||
|
||||
filterChainDefinitionMap.put("/display/info", "anon");
|
||||
filterChainDefinitionMap.put("/favicon.ico", "anon");
|
||||
filterChainDefinitionMap.put("/display/file/**", "anon");
|
||||
filterChainDefinitionMap.put("/jmeter/download/**", "anon");
|
||||
filterChainDefinitionMap.put("/authsource/list/allenable", "anon");
|
||||
filterChainDefinitionMap.put("/sso/signin", "anon");
|
||||
// for swagger
|
||||
filterChainDefinitionMap.put("/swagger-ui.html", "anon");
|
||||
filterChainDefinitionMap.put("/swagger-ui/**", "anon");
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package io.metersphere.config;
|
||||
|
||||
import io.metersphere.commons.user.UserModularRealmAuthenticator;
|
||||
import io.metersphere.commons.utils.ShiroUtils;
|
||||
import io.metersphere.security.ApiKeyFilter;
|
||||
import io.metersphere.security.LdapRealm;
|
||||
import io.metersphere.security.ShiroDBRealm;
|
||||
import io.metersphere.security.UserModularRealmAuthenticator;
|
||||
import io.metersphere.security.realm.LdapRealm;
|
||||
import io.metersphere.security.realm.ShiroDBRealm;
|
||||
import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
|
||||
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
|
||||
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
|
||||
|
@ -46,10 +46,7 @@ public class ShiroConfig implements EnvironmentAware {
|
|||
shiroFilterFactoryBean.getFilters().put("apikey", new ApiKeyFilter());
|
||||
Map<String, String> filterChainDefinitionMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
|
||||
ShiroUtils.loadBaseFilterChain(filterChainDefinitionMap);
|
||||
filterChainDefinitionMap.put("/display/info", "anon");
|
||||
filterChainDefinitionMap.put("/favicon.ico", "anon");
|
||||
filterChainDefinitionMap.put("/display/file/**", "anon");
|
||||
filterChainDefinitionMap.put("/jmeter/download/**", "anon");
|
||||
|
||||
filterChainDefinitionMap.put("/**", "apikey, authc");
|
||||
return shiroFilterFactoryBean;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.metersphere.controller;
|
||||
|
||||
import io.metersphere.commons.utils.SessionUtils;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
@ -23,15 +22,4 @@ public class IndexController {
|
|||
return "redirect:/";
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping(value = "/sso/login")
|
||||
public String ossLogin() {
|
||||
return "redirect:/";
|
||||
}
|
||||
|
||||
@GetMapping(value = "/sso/logout")
|
||||
public void ossLogout() {
|
||||
SecurityUtils.getSubject().logout();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,4 +8,5 @@ import lombok.Setter;
|
|||
public class LoginRequest {
|
||||
private String username;
|
||||
private String password;
|
||||
private String authenticate;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package io.metersphere.security;
|
||||
|
||||
import io.metersphere.commons.user.MsUserToken;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package io.metersphere.commons.user;
|
||||
package io.metersphere.security;
|
||||
|
||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package io.metersphere.commons.user;
|
||||
package io.metersphere.security;
|
||||
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
|
@ -1,4 +1,4 @@
|
|||
package io.metersphere.security;
|
||||
package io.metersphere.security.realm;
|
||||
|
||||
|
||||
import io.metersphere.base.domain.Role;
|
|
@ -1,4 +1,4 @@
|
|||
package io.metersphere.security;
|
||||
package io.metersphere.security.realm;
|
||||
|
||||
|
||||
import io.metersphere.base.domain.Role;
|
|
@ -8,7 +8,6 @@ import io.metersphere.commons.constants.RoleConstants;
|
|||
import io.metersphere.commons.constants.UserSource;
|
||||
import io.metersphere.commons.constants.UserStatus;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.user.MsUserToken;
|
||||
import io.metersphere.commons.user.SessionUser;
|
||||
import io.metersphere.commons.utils.CodingUtil;
|
||||
import io.metersphere.commons.utils.SessionUtils;
|
||||
|
@ -24,6 +23,7 @@ import io.metersphere.dto.UserDTO;
|
|||
import io.metersphere.dto.UserRoleDTO;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import io.metersphere.notice.domain.UserDetail;
|
||||
import io.metersphere.security.MsUserToken;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authc.*;
|
||||
|
@ -559,16 +559,14 @@ public class UserService {
|
|||
String login = (String) SecurityUtils.getSubject().getSession().getAttribute("authenticate");
|
||||
String username = StringUtils.trim(request.getUsername());
|
||||
String password = "";
|
||||
String loginType = UserSource.LDAP.name();
|
||||
if (!StringUtils.equals(login, UserSource.LDAP.name())) {
|
||||
loginType = UserSource.LOCAL.name();
|
||||
password = StringUtils.trim(request.getPassword());
|
||||
if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
|
||||
return ResultHolder.error("user or password can't be null");
|
||||
}
|
||||
}
|
||||
|
||||
MsUserToken token = new MsUserToken(username, password, loginType);
|
||||
MsUserToken token = new MsUserToken(username, password, login);
|
||||
Subject subject = SecurityUtils.getSubject();
|
||||
try {
|
||||
subject.login(token);
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 36116c1bff736377e6b8a3b828c5fa9bd8b2f2f8
|
||||
Subproject commit c2ed883e9be6fc7e01589f81916bf4ddc62148c0
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<el-dropdown size="medium" @command="handleCommand" class="align-right">
|
||||
<span class="dropdown-link">
|
||||
{{currentUser.name}}<i class="el-icon-caret-bottom el-icon--right"/>
|
||||
{{ currentUser.name }}<i class="el-icon-caret-bottom el-icon--right"/>
|
||||
</span>
|
||||
<template v-slot:dropdown>
|
||||
<el-dropdown-menu>
|
||||
|
@ -23,82 +23,77 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {getCurrentUser} from "../../../../common/js/utils";
|
||||
import AboutUs from "./AboutUs";
|
||||
import axios from "axios";
|
||||
import {getCurrentUser} from "@/common/js/utils";
|
||||
import AboutUs from "./AboutUs";
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
name: "MsUser",
|
||||
components: {AboutUs},
|
||||
data() {
|
||||
return {
|
||||
isReadOnly: this.$store.state.isReadOnly.flag
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentUser: () => {
|
||||
return getCurrentUser();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleCommand(command) {
|
||||
switch (command) {
|
||||
case "personal":
|
||||
// TODO 优化路由跳转,避免重复添加路由
|
||||
this.$router.push('/setting/personsetting').catch(error => error);
|
||||
break;
|
||||
case "logout":
|
||||
axios.get("/signout").then(response => {
|
||||
if (response.data.success) {
|
||||
localStorage.clear();
|
||||
window.location.href = "/login";
|
||||
} else {
|
||||
if (response.data.message === 'sso') {
|
||||
localStorage.clear();
|
||||
window.location.href = "/sso/logout"
|
||||
}
|
||||
}
|
||||
}).catch(error => {
|
||||
export default {
|
||||
name: "MsUser",
|
||||
components: {AboutUs},
|
||||
data() {
|
||||
return {
|
||||
isReadOnly: this.$store.state.isReadOnly.flag
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentUser: () => {
|
||||
return getCurrentUser();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleCommand(command) {
|
||||
switch (command) {
|
||||
case "personal":
|
||||
// TODO 优化路由跳转,避免重复添加路由
|
||||
this.$router.push('/setting/personsetting').catch(error => error);
|
||||
break;
|
||||
case "logout":
|
||||
axios.get("/signout").then(response => {
|
||||
if (response.data.success) {
|
||||
localStorage.clear();
|
||||
window.location.href = "/login";
|
||||
});
|
||||
break;
|
||||
case "about":
|
||||
this.$refs.aboutUs.open();
|
||||
break;
|
||||
case "help":
|
||||
window.location.href = "https://metersphere.io/docs/index.html";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
changeBar(item) {
|
||||
this.isReadOnly = !this.isReadOnly
|
||||
this.$store.commit('setFlag', this.isReadOnly);
|
||||
this.$store.commit('setValue', item);
|
||||
if(item=="old"){
|
||||
window.location.href = "/#/api/home_obsolete";
|
||||
}else {
|
||||
window.location.href = "/#/api/home";
|
||||
}
|
||||
|
||||
}
|
||||
}).catch(error => {
|
||||
localStorage.clear();
|
||||
window.location.href = "/login";
|
||||
});
|
||||
break;
|
||||
case "about":
|
||||
this.$refs.aboutUs.open();
|
||||
break;
|
||||
case "help":
|
||||
window.location.href = "https://metersphere.io/docs/index.html";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
changeBar(item) {
|
||||
this.isReadOnly = !this.isReadOnly
|
||||
this.$store.commit('setFlag', this.isReadOnly);
|
||||
this.$store.commit('setValue', item);
|
||||
if (item == "old") {
|
||||
window.location.href = "/#/api/home_obsolete";
|
||||
} else {
|
||||
window.location.href = "/#/api/home";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dropdown-link {
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
color: rgb(245, 245, 245);
|
||||
line-height: 40px;
|
||||
}
|
||||
.dropdown-link {
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
color: rgb(245, 245, 245);
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
.align-right {
|
||||
float: right;
|
||||
}
|
||||
.align-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 3d96d7c61bc50f32f18311d23f447663e02d7d44
|
||||
Subproject commit cea763d974b213104f6d6fc30ab48434b72e10f4
|
|
@ -18,6 +18,7 @@
|
|||
<el-radio-group v-model="form.authenticate">
|
||||
<el-radio label="LDAP" size="mini" v-if="openLdap">LDAP</el-radio>
|
||||
<el-radio label="LOCAL" size="mini" v-if="openLdap">普通登录</el-radio>
|
||||
<el-radio :label="auth.id" size="mini" v-for="auth in authSources" :key="auth.id">{{ auth.type }} {{ auth.name }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item prop="username">
|
||||
|
@ -52,6 +53,7 @@ import {DEFAULT_LANGUAGE} from "@/common/js/constants";
|
|||
|
||||
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
|
||||
const display = requireComponent.keys().length > 0 ? requireComponent("./display/Display.vue") : {};
|
||||
const auth = requireComponent.keys().length > 0 ? requireComponent("./auth/Auth.vue") : {};
|
||||
|
||||
export default {
|
||||
name: "Login",
|
||||
|
@ -84,7 +86,9 @@ export default {
|
|||
msg: '',
|
||||
ready: false,
|
||||
openLdap: false,
|
||||
loginTitle: this.$t("commons.login") + " MeterSphere"
|
||||
loginTitle: this.$t("commons.login") + " MeterSphere",
|
||||
authSources: [],
|
||||
loginUrl: 'signin',
|
||||
}
|
||||
},
|
||||
beforeCreate() {
|
||||
|
@ -94,17 +98,17 @@ export default {
|
|||
display.default.showLogin(this);
|
||||
}
|
||||
|
||||
if (auth.default !== undefined) {
|
||||
auth.default.getAuthSources(this);
|
||||
}
|
||||
|
||||
if (!response.data.success) {
|
||||
if (response.data.message === 'sso') {
|
||||
window.location.href = "/sso/login"
|
||||
} else {
|
||||
this.ready = true;
|
||||
}
|
||||
this.ready = true;
|
||||
} else {
|
||||
let user = response.data.data;
|
||||
saveLocalStorage(response.data);
|
||||
this.getLanguage(user.language);
|
||||
window.location.href = "/"
|
||||
window.location.href = "/";
|
||||
}
|
||||
});
|
||||
this.$get("/ldap/open", response => {
|
||||
|
@ -135,28 +139,24 @@ export default {
|
|||
if (valid) {
|
||||
switch (this.form.authenticate) {
|
||||
case "LOCAL":
|
||||
this.normalLogin();
|
||||
this.loginUrl = "/signin";
|
||||
this.doLogin();
|
||||
break;
|
||||
case "LDAP":
|
||||
this.ldapLogin();
|
||||
this.loginUrl = "/ldap/signin";
|
||||
this.doLogin();
|
||||
break;
|
||||
default:
|
||||
this.normalLogin();
|
||||
this.loginUrl = "/sso/signin";
|
||||
this.doLogin();
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
normalLogin() {
|
||||
this.result = this.$post("signin", this.form, response => {
|
||||
saveLocalStorage(response);
|
||||
sessionStorage.setItem('loginSuccess', 'true');
|
||||
this.getLanguage(response.data.language);
|
||||
});
|
||||
},
|
||||
ldapLogin() {
|
||||
this.result = this.$post("ldap/signin", this.form, response => {
|
||||
doLogin() {
|
||||
this.result = this.$post(this.loginUrl, this.form, response => {
|
||||
saveLocalStorage(response);
|
||||
sessionStorage.setItem('loginSuccess', 'true');
|
||||
this.getLanguage(response.data.language);
|
||||
|
|
Loading…
Reference in New Issue