项目需求、任务以及模块精简

This commit is contained in:
2026-04-04 19:00:25 +08:00
parent 787c82d30c
commit 953bdf6bbb
895 changed files with 141589 additions and 67010 deletions

View File

@@ -122,13 +122,6 @@
<version>${project.parent.version}</version>
</dependency>
<!-- CAS 单点登录模块 -->
<dependency>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-module-cas</artifactId>
<version>${project.parent.version}</version>
</dependency>
<!-- ELK 日志收集 -->
<dependency>
<groupId>net.logstash.logback</groupId>

View File

@@ -6,12 +6,9 @@ package com.jeesite.autoconfigure.core;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.config.Global;
import com.jeesite.common.shiro.cas.CasOutHandler;
import com.jeesite.common.shiro.cas.CasSubjectFactory;
import com.jeesite.common.shiro.config.FilterChainDefinitionMap;
import com.jeesite.common.shiro.filter.*;
import com.jeesite.common.shiro.realm.AuthorizingRealm;
import com.jeesite.common.shiro.realm.CasAuthorizingRealm;
import com.jeesite.common.shiro.realm.LdapAuthorizingRealm;
import com.jeesite.common.shiro.session.SessionDAO;
import com.jeesite.common.shiro.session.SessionManager;
@@ -68,15 +65,6 @@ public class ShiroAutoConfiguration {
return new InnerFilter();
}
/**
* CAS登录过滤器
*/
private CasFilter shiroCasFilter(CasAuthorizingRealm casAuthorizingRealm) {
CasFilter bean = new CasFilter();
bean.setAuthorizingRealm(casAuthorizingRealm);
return bean;
}
/**
* LDAP登录过滤器
*/
@@ -140,14 +128,13 @@ public class ShiroAutoConfiguration {
@Bean("shiroFilter")
@ConditionalOnMissingBean(name="shiroFilter")
public ShiroFilterFactoryBean shiroFilter(WebSecurityManager webSecurityManager, AuthorizingRealm authorizingRealm,
CasAuthorizingRealm casAuthorizingRealm, LdapAuthorizingRealm ldapAuthorizingRealm) {
LdapAuthorizingRealm ldapAuthorizingRealm) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(webSecurityManager);
bean.setLoginUrl(Global.getProperty("shiro.loginUrl"));
bean.setSuccessUrl(Global.getProperty("adminPath")+"/index");
Map<String, Filter> filters = bean.getFilters();
filters.put("inner", shiroInnerFilter());
filters.put("cas", shiroCasFilter(casAuthorizingRealm));
filters.put("ldap", shiroLdapFilter(ldapAuthorizingRealm));
filters.put("authc", shiroAuthcFilter(authorizingRealm));
filters.put("logout", shiroLogoutFilter(authorizingRealm));
@@ -173,35 +160,12 @@ public class ShiroAutoConfiguration {
return bean;
}
/**
* 单点登录信息句柄,单点退出用
*/
@Bean("casOutHandler")
@ConditionalOnMissingBean(name="casOutHandler")
public CasOutHandler casOutHandler() {
return new CasOutHandler();
}
/**
* CAS安全认证实现类
*/
@Bean("casAuthorizingRealm")
@ConditionalOnMissingBean(name="casAuthorizingRealm")
public CasAuthorizingRealm casAuthorizingRealm(@Qualifier("sessionDAO") SessionDAO sessionDAO, CasOutHandler casOutHandler) {
CasAuthorizingRealm bean = new CasAuthorizingRealm();
bean.setSessionDAO(sessionDAO);
bean.setCasOutHandler(casOutHandler);
bean.setCasServerUrl(Global.getProperty("shiro.casServerUrl"));
bean.setCasServerCallbackUrl(Global.getProperty("shiro.casClientUrl") + Global.getAdminPath() + "/login-cas");
return bean;
}
/**
* LDAP安全认证实现类
*/
@Bean("ldapAuthorizingRealm")
@ConditionalOnMissingBean(name="ldapAuthorizingRealm")
public LdapAuthorizingRealm ldapAuthorizingRealm(@Qualifier("sessionDAO") SessionDAO sessionDAO, CasOutHandler casOutHandler) {
public LdapAuthorizingRealm ldapAuthorizingRealm(@Qualifier("sessionDAO") SessionDAO sessionDAO) {
LdapAuthorizingRealm bean = new LdapAuthorizingRealm();
JndiLdapContextFactory contextFactory = (JndiLdapContextFactory) bean.getContextFactory();
contextFactory.setUrl(Global.getProperty("shiro.ldapUrl"/*, "ldap://127.0.0.1:389"*/));
@@ -215,17 +179,15 @@ public class ShiroAutoConfiguration {
*/
@Bean("webSecurityManager")
@ConditionalOnMissingBean(name="webSecurityManager")
public WebSecurityManager webSecurityManager(AuthorizingRealm authorizingRealm, CasAuthorizingRealm casAuthorizingRealm,
public WebSecurityManager webSecurityManager(AuthorizingRealm authorizingRealm,
LdapAuthorizingRealm ldapAuthorizingRealm, SessionManager sessionManager, @Qualifier("shiroCacheManager") CacheManager shiroCacheManager) {
WebSecurityManager bean = new WebSecurityManager();
Collection<Realm> realms = ListUtils.newArrayList();
realms.add(authorizingRealm); // 第一个为权限授权控制类
realms.add(casAuthorizingRealm);
realms.add(ldapAuthorizingRealm);
bean.setRealms(realms);
bean.setSessionManager(sessionManager);
bean.setCacheManager(shiroCacheManager);
bean.setSubjectFactory(new CasSubjectFactory());
//bean.setRememberMeManager(null); // 关闭 RememberMe
return bean;
}

View File

@@ -1,81 +0,0 @@
/**
* Copyright (c) 2013-Now https://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
*/
package com.jeesite.common.shiro.filter;
import com.jeesite.common.config.Global;
import com.jeesite.common.lang.ExceptionUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.shiro.cas.CasBaseFilter;
import com.jeesite.common.shiro.realm.BaseAuthorizingRealm;
import com.jeesite.common.web.http.ServletUtils;
import com.jeesite.modules.sys.utils.UserUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* CAS过滤器
* @author ThinkGem
* @version 2020-9-19
*/
@SuppressWarnings("deprecation")
public class CasFilter extends CasBaseFilter {
private static final Logger logger = LoggerFactory.getLogger(CasFilter.class);
private BaseAuthorizingRealm authorizingRealm;
public CasFilter() {
this.setSuccessUrl(Global.getProperty("shiro.successUrl"));
}
/**
* 登录成功调用事件
*/
@Override
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
authorizingRealm.onLoginSuccess(UserUtils.getLoginInfo(subject), (HttpServletRequest)request);
ServletUtils.redirectUrl((HttpServletRequest)request, (HttpServletResponse)response, getSuccessUrl());
return false;
}
/**
* 登录失败调用事件
*/
@Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException ae, ServletRequest request, ServletResponse response) {
Subject subject = getSubject(request, response);
if (subject.isAuthenticated() || subject.isRemembered()) {
ServletUtils.redirectUrl((HttpServletRequest)request, (HttpServletResponse)response, getSuccessUrl());
return false;
} else {
try {
String message = ExceptionUtils.getExceptionMessage(ae);
if (StringUtils.isNotBlank(message)){
request.setAttribute("exception", ae);
request.setAttribute("message", message);
request.getRequestDispatcher("/error/403").forward(request, response);
}else{
WebUtils.issueRedirect(request, response, getLoginUrl());
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return false;
}
}
public void setAuthorizingRealm(BaseAuthorizingRealm authorizingRealm) {
this.authorizingRealm = authorizingRealm;
}
}

View File

@@ -1,217 +0,0 @@
/**
* Copyright (c) 2013-Now https://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
*/
package com.jeesite.common.shiro.realm;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.collect.MapUtils;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.shiro.authc.FormToken;
import com.jeesite.common.shiro.cas.CasCreateUser;
import com.jeesite.common.shiro.cas.CasOutHandler;
import com.jeesite.common.shiro.cas.CasToken;
import com.jeesite.common.utils.SpringUtils;
import com.jeesite.common.web.http.ServletUtils;
import com.jeesite.modules.sys.entity.EmpUser;
import com.jeesite.modules.sys.entity.Log;
import com.jeesite.modules.sys.entity.User;
import com.jeesite.modules.sys.service.EmpUserService;
import com.jeesite.modules.sys.utils.LogUtils;
import com.jeesite.modules.sys.utils.UserUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ValidationException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.jasig.cas.client.validation.TicketValidationException;
import org.jasig.cas.client.validation.TicketValidator;
import java.util.Map;
/**
* 系统认证授权实现类
* @author ThinkGem
* @version 2020-9-19
*/
@SuppressWarnings("deprecation")
public class CasAuthorizingRealm extends BaseAuthorizingRealm {
private CasOutHandler casOutHandler;
private String casServerUrl; // CAS 服务器地址
private String casServerCallbackUrl; // CAS 服务器回调地址
private TicketValidator ticketValidator;// CAS 令牌验证类
private EmpUserService empUserService;
public CasAuthorizingRealm() {
super();
this.setAuthenticationTokenClass(CasToken.class);
}
@Override
protected FormToken getFormToken(AuthenticationToken authcToken) {
// 单点登录登出句柄登出时注销session有CAS中央服务器调用
HttpServletRequest request = ServletUtils.getRequest();
if (casOutHandler.isLogoutRequest(request)) {
LoginInfo loginInfo = casOutHandler.destroySession(request);
if (loginInfo != null){
this.onLogoutSuccess(loginInfo, request);
}
return null;
}
if (authcToken == null){
return null;
}
CasToken casToken = (CasToken) authcToken;
String ticket = (String) casToken.getCredentials();
if (ticketValidator == null) {
ticketValidator = new Cas20ServiceTicketValidator(casServerUrl);
((Cas20ServiceTicketValidator)ticketValidator).setEncoding(EncodeUtils.UTF_8);
}
// 进行登录身份验证
Assertion casAssertion = null;
try {
casAssertion = ticketValidator.validate(ticket, casServerCallbackUrl);
} catch (TicketValidationException e) {
// 令牌失效在LogoutFilter会自动跳转到登录页
return null;
}
AttributePrincipal casPrincipal = casAssertion.getPrincipal();
casToken.setUserId(casPrincipal.getName());
// 生成登录信息对象
FormToken token = new FormToken(request);
token.setUsername(casPrincipal.getName());
Map<String, Object> params = MapUtils.newHashMap();
params.putAll(casPrincipal.getAttributes());
params.put("ticket", ticket);
token.setParams(params);
return token;
}
@Override
protected User getUserInfo(FormToken token) {
User user = super.getUserInfo(token);
if (user == null){
Map<String, Object> attrs = token.getParams();
// 如果允许客户端创建账号,则创建账号
if (ObjectUtils.toBoolean(attrs.get("isAllowClientCreateUser"))){
// 获取CAS传递过来的用户属性信息
user = new User(EncodeUtils.decodeUrl(ObjectUtils.toString(attrs.get("userCode"))));
user.setLoginCode(EncodeUtils.decodeUrl(ObjectUtils.toString(attrs.get("loginCode"))));
user.setCorpCode_(EncodeUtils.decodeUrl(ObjectUtils.toString(attrs.get("corpCode"))));
user.setPassword(EncodeUtils.decodeUrl(ObjectUtils.toString(attrs.get("password"))));
user.setUserName(EncodeUtils.decodeUrl(ObjectUtils.toString(attrs.get("userName"))));
user.setEmail(EncodeUtils.decodeUrl(ObjectUtils.toString(attrs.get("email"))));
user.setMobile(EncodeUtils.decodeUrl(ObjectUtils.toString(attrs.get("mobile"))));
user.setPhone(EncodeUtils.decodeUrl(ObjectUtils.toString(attrs.get("phone"))));
user.setUserType(EncodeUtils.decodeUrl(ObjectUtils.toString(attrs.get("userType"))));
user.setRefCode(EncodeUtils.decodeUrl(ObjectUtils.toString(attrs.get("refCode"))));
user.setRefName(EncodeUtils.decodeUrl(ObjectUtils.toString(attrs.get("refName"))));
user.setMgrType(EncodeUtils.decodeUrl(ObjectUtils.toString(attrs.get("mgrType"))));
user.setStatus(EncodeUtils.decodeUrl(ObjectUtils.toString(attrs.get("status"))));
// 如果是员工类型,则平台自动创建
if (User.USER_TYPE_EMPLOYEE.equals(user.getUserType())){
// 保存员工和用户
try{
EmpUser empUser = new EmpUser();
empUser.setIsNewRecord(true);
empUser.setMobile(user.getMobile());
empUser.setEmail(user.getEmail());
empUser.setPhone(user.getPhone());
empUser.getEmployee().getCompany().setCompanyCode(EncodeUtils
.decodeUrl(ObjectUtils.toString(attrs.get("companyCode"))));
empUser.getEmployee().getOffice().setOfficeCode(EncodeUtils
.decodeUrl(ObjectUtils.toString(attrs.get("officeCode"))));
getEmpUserService().save(empUser);
}catch(ValidationException ve){
throw new AuthenticationException("msg:" + ve.getMessage());
}
// 重新获取用户登录
user = UserUtils.getByLoginCode(token.getUsername(), user.getCorpCode_());
if (user != null) {
return user;
}
}
// 其它类型,根据项目需要自行创建
else{
User finalUser = user;
SpringUtils.getBeanIfAvailable(CasCreateUser.class, (casCreateUser) -> {
casCreateUser.createUser(finalUser, attrs);
}, (e -> {
throw new AuthenticationException("msg:用户 “" + token.getUsername()
+ "”, 类型 “" + finalUser.getUserType() + "” 在本系统中不存在, 请联系管理员.");
}));
}
}else{
throw new AuthenticationException("msg:用户 “" + token.getUsername() + "” 在本系统中不存在, 请联系管理员.");
}
}
return user;
}
@Override
protected void assertCredentialsMatch(AuthenticationToken authcToken,
AuthenticationInfo info) throws AuthenticationException {
// 已经在 getFormToken 认证过了,这里就不验证身份了
}
@Override
public User onLoginSuccess(LoginInfo loginInfo, HttpServletRequest request) {
User user = super.onLoginSuccess(loginInfo, request);
// 单点登录登出句柄登录时注入session在这之前必须获取下授权信息
String ticket = loginInfo.getParam("ticket");
casOutHandler.recordSession(request, ticket);
//System.out.print("__sid: "+request.getSession().getId());
//System.out.println(" == "+UserUtils.getSession().getId());
// 记录用户登录日志
LogUtils.saveLog(user, request, "系统登录", Log.TYPE_LOGIN_LOGOUT);
return user;
}
@Override
public User onLogoutSuccess(LoginInfo loginInfo, HttpServletRequest request) {
User user = super.onLogoutSuccess(loginInfo, request);
// 记录用户退出日志
LogUtils.saveLog(user, request, "系统退出", Log.TYPE_LOGIN_LOGOUT);
return user;
}
public EmpUserService getEmpUserService() {
if (empUserService == null){
empUserService = SpringUtils.getBean(EmpUserService.class);
}
return empUserService;
}
public void setCasOutHandler(CasOutHandler casOutHandler) {
this.casOutHandler = casOutHandler;
}
public void setCasServerUrl(String casServerUrl) {
this.casServerUrl = casServerUrl;
}
public void setCasServerCallbackUrl(String casServerCallbackUrl) {
this.casServerCallbackUrl = casServerCallbackUrl;
}
}

View File

@@ -570,7 +570,6 @@ shiro:
/bpm/modeler/** = perms[bpm:modeler]
/ureport/designer/** = perms[ureport]
/ureport/datasource/** = perms[ureport]
${adminPath}/login-cas = cas
${adminPath}/login-ldap = ldap
${adminPath}/login = authc
${adminPath}/logout = logout