first commit
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
package com.budwk.app.web.commons.auth.cas;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.mvc.ActionContext;
|
||||
import org.nutz.mvc.ActionFilter;
|
||||
import org.nutz.mvc.View;
|
||||
import org.nutz.mvc.impl.processor.AbstractProcessor;
|
||||
|
||||
@Slf4j
|
||||
public class CasAuthFilter extends AbstractProcessor implements ActionFilter {
|
||||
|
||||
@Override
|
||||
public View match(ActionContext actionContext) {
|
||||
log.debug("match? maybe.");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ActionContext actionContext) throws Throwable {
|
||||
log.debug("before doNext");
|
||||
doNext(actionContext);
|
||||
log.debug("after doNext");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.budwk.app.web.commons.auth.cas;
|
||||
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
@IocBean
|
||||
public class CasConfig{
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.budwk.app.web.commons.auth.satoken;
|
||||
|
||||
import cn.dev33.satoken.context.SaTokenContext;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.context.model.SaResponse;
|
||||
import cn.dev33.satoken.context.model.SaStorage;
|
||||
import cn.dev33.satoken.servlet.model.SaRequestForServlet;
|
||||
import cn.dev33.satoken.servlet.model.SaResponseForServlet;
|
||||
import cn.dev33.satoken.servlet.model.SaStorageForServlet;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.Mvcs;
|
||||
|
||||
/**
|
||||
* @author wizzer@qq.com
|
||||
*/
|
||||
@IocBean
|
||||
public class SaTokenContextImpl implements SaTokenContext {
|
||||
@Override
|
||||
public SaRequest getRequest() {
|
||||
return new SaRequestForServlet(Mvcs.getReq());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SaResponse getResponse() {
|
||||
return new SaResponseForServlet(Mvcs.getResp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SaStorage getStorage() {
|
||||
return new SaStorageForServlet(Mvcs.getReq());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchPath(String pattern, String path) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package com.budwk.app.web.commons.auth.satoken;
|
||||
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import com.budwk.app.base.constant.RedisConstant;
|
||||
import org.nutz.integration.jedis.RedisService;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Lang;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author wizzer@qq.com
|
||||
*/
|
||||
@IocBean
|
||||
public class SaTokenDaoRedisImpl implements SaTokenDao {
|
||||
|
||||
@Inject
|
||||
private RedisService redisService;
|
||||
|
||||
@Override
|
||||
public String get(String key) {
|
||||
return redisService.get(RedisConstant.TOKEN + key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(String key, String value, long timeout) {
|
||||
if (timeout == SaTokenDao.NEVER_EXPIRE) {
|
||||
redisService.set(RedisConstant.TOKEN + key, value);
|
||||
} else {
|
||||
redisService.setex(RedisConstant.TOKEN + key, (int) timeout, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(String key, String value) {
|
||||
long expire = this.getTimeout(key);
|
||||
// -2 = 无此键
|
||||
if (expire == SaTokenDao.NOT_VALUE_EXPIRE) {
|
||||
return;
|
||||
}
|
||||
this.set(key, value, expire);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String key) {
|
||||
redisService.del(RedisConstant.TOKEN + key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeout(String key) {
|
||||
return redisService.ttl(RedisConstant.TOKEN + key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTimeout(String key, long timeout) {
|
||||
// 判断是否想要设置为永久
|
||||
if (timeout == SaTokenDao.NEVER_EXPIRE) {
|
||||
long expire = this.getTimeout(key);
|
||||
if (expire == SaTokenDao.NEVER_EXPIRE) {
|
||||
// 如果其已经被设置为永久,则不作任何处理
|
||||
} else {
|
||||
// 如果尚未被设置为永久,那么再次set一次
|
||||
this.set(key, this.get(key), timeout);
|
||||
}
|
||||
return;
|
||||
}
|
||||
redisService.expire(RedisConstant.TOKEN + key, (int) timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject(String key) {
|
||||
byte[] bytes = redisService.get((RedisConstant.TOKEN + key).getBytes(StandardCharsets.UTF_8));
|
||||
if (bytes != null) {
|
||||
return Lang.fromBytes(bytes, Object.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObject(String key, Object value, long timeout) {
|
||||
// 判断是否为永不过期
|
||||
if (timeout == SaTokenDao.NEVER_EXPIRE) {
|
||||
redisService.set((RedisConstant.TOKEN + key).getBytes(StandardCharsets.UTF_8), Lang.toBytes(value));
|
||||
} else {
|
||||
redisService.setex((RedisConstant.TOKEN + key).getBytes(StandardCharsets.UTF_8), (int) timeout, Lang.toBytes(value));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateObject(String key, Object object) {
|
||||
long expire = this.getObjectTimeout(key);
|
||||
// -2 = 无此键
|
||||
if (expire == SaTokenDao.NOT_VALUE_EXPIRE) {
|
||||
return;
|
||||
}
|
||||
this.setObject(key, object, expire);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteObject(String key) {
|
||||
redisService.del((RedisConstant.TOKEN + key).getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getObjectTimeout(String key) {
|
||||
return redisService.ttl((RedisConstant.TOKEN + key).getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateObjectTimeout(String key, long timeout) {
|
||||
// 判断是否想要设置为永久
|
||||
if (timeout == SaTokenDao.NEVER_EXPIRE) {
|
||||
long expire = getObjectTimeout(key);
|
||||
if (expire == SaTokenDao.NEVER_EXPIRE) {
|
||||
// 如果其已经被设置为永久,则不作任何处理
|
||||
} else {
|
||||
// 如果尚未被设置为永久,那么再次set一次
|
||||
this.setObject(key, this.getObject(key), timeout);
|
||||
}
|
||||
return;
|
||||
}
|
||||
redisService.expire((RedisConstant.TOKEN + key).getBytes(StandardCharsets.UTF_8), (int) timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> searchData(String prefix, String keyword, int start, int size) {
|
||||
Set<String> keys = redisService.keys(RedisConstant.TOKEN + prefix + "*" + keyword + "*");
|
||||
List<String> list = new ArrayList<>(keys);
|
||||
return SaFoxUtil.searchList(list, start, size);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.budwk.app.web.commons.auth.satoken;
|
||||
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
import com.budwk.app.sys.services.SysUserService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.ioc.Ioc;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Strings;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author wizzer@qq.com
|
||||
*/
|
||||
@IocBean
|
||||
@Slf4j
|
||||
public class StpInterfaceImpl implements StpInterface {
|
||||
@Inject
|
||||
private SysUserService sysUserService;
|
||||
@Inject("refer:$ioc")
|
||||
protected Ioc ioc;
|
||||
|
||||
@Override
|
||||
public List<String> getPermissionList(Object loginId, String loginKey) {
|
||||
return sysUserService.getPermissionList(Strings.sNull(loginId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRoleList(Object loginId, String loginKey) {
|
||||
return sysUserService.getRoleCodeList(sysUserService.fetch(Strings.sNull(loginId)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.budwk.app.web.commons.auth.satoken.aop;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import org.nutz.aop.InterceptorChain;
|
||||
import org.nutz.aop.MethodInterceptor;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author wizzer@qq.com
|
||||
*/
|
||||
@IocBean(singleton = false)
|
||||
public class SaCheckLoginInterceptor implements MethodInterceptor {
|
||||
@Override
|
||||
public void filter(InterceptorChain chain) throws Throwable {
|
||||
Method method = chain.getCallingMethod();
|
||||
SaCheckLogin at = method.getAnnotation(SaCheckLogin.class);
|
||||
SaManager.getStpLogic(at.type()).checkByAnnotation(at);
|
||||
chain.doChain();
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.budwk.app.web.commons.auth.satoken.aop;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.nutz.aop.InterceptorChain;
|
||||
import org.nutz.aop.MethodInterceptor;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author wizzer@qq.com
|
||||
*/
|
||||
@IocBean(singleton = false)
|
||||
public class SaCheckPermissionInterceptor implements MethodInterceptor {
|
||||
@Override
|
||||
public void filter(InterceptorChain chain) throws Throwable {
|
||||
Method method = chain.getCallingMethod();
|
||||
SaCheckPermission at = method.getAnnotation(SaCheckPermission.class);
|
||||
SaManager.getStpLogic(at.type()).checkByAnnotation(at);
|
||||
chain.doChain();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.budwk.app.web.commons.auth.satoken.aop;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.annotation.SaCheckRole;
|
||||
import org.nutz.aop.InterceptorChain;
|
||||
import org.nutz.aop.MethodInterceptor;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author wizzer@qq.com
|
||||
*/
|
||||
@IocBean(singleton = false)
|
||||
public class SaCheckRoleInterceptor implements MethodInterceptor {
|
||||
@Override
|
||||
public void filter(InterceptorChain chain) throws Throwable {
|
||||
Method method = chain.getCallingMethod();
|
||||
SaCheckRole at = method.getAnnotation(SaCheckRole.class);
|
||||
SaManager.getStpLogic(at.type()).checkByAnnotation(at);
|
||||
chain.doChain();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.budwk.app.web.commons.auth.satoken.aop;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaCheckRole;
|
||||
import org.nutz.ioc.Ioc;
|
||||
import org.nutz.ioc.aop.config.AopConfigration;
|
||||
import org.nutz.ioc.aop.config.InterceptorPair;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author wizzer@qq.com
|
||||
*/
|
||||
@IocBean(name = "$aop_satoken")
|
||||
public class SaTokenAopConfigration implements AopConfigration {
|
||||
|
||||
@Override
|
||||
public List<InterceptorPair> getInterceptorPairList(Ioc ioc, Class<?> clazz) {
|
||||
List<InterceptorPair> list = new ArrayList<InterceptorPair>();
|
||||
boolean flag = true;
|
||||
for (Method method : clazz.getMethods()) {
|
||||
if (method.getAnnotation(SaCheckLogin.class) != null
|
||||
|| method.getAnnotation(SaCheckRole.class) != null
|
||||
|| method.getAnnotation(SaCheckPermission.class) != null) {
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag)
|
||||
return list;
|
||||
list.add(new InterceptorPair(ioc.get(SaCheckLoginInterceptor.class),
|
||||
new SaTokenMethodMatcher(SaCheckLogin.class)));
|
||||
list.add(new InterceptorPair(ioc.get(SaCheckRoleInterceptor.class),
|
||||
new SaTokenMethodMatcher(SaCheckRole.class)));
|
||||
list.add(new InterceptorPair(ioc.get(SaCheckPermissionInterceptor.class),
|
||||
new SaTokenMethodMatcher(SaCheckPermission.class)));
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.budwk.app.web.commons.auth.satoken.aop;
|
||||
|
||||
import org.nutz.aop.MethodMatcher;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author wizzer@qq.com
|
||||
*/
|
||||
public class SaTokenMethodMatcher implements MethodMatcher {
|
||||
|
||||
protected Class<? extends Annotation> klass;
|
||||
|
||||
public SaTokenMethodMatcher(Class<? extends Annotation> klass) {
|
||||
this.klass = klass;
|
||||
}
|
||||
|
||||
public boolean match(Method method) {
|
||||
return method.getAnnotation(klass) != null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.budwk.app.web.commons.auth.service;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import com.budwk.app.base.utils.SysMenuUtil;
|
||||
import com.budwk.app.sys.models.Sys_menu;
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
import com.budwk.app.sys.services.SysUserService;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.json.Json;
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author wizzer@qq.com
|
||||
*/
|
||||
@IocBean
|
||||
@Slf4j
|
||||
public class AuthService {
|
||||
@Inject
|
||||
private SysUserService sysUserService;
|
||||
|
||||
public Sys_user getLogonUser() {
|
||||
return sysUserService.getUserAndMenuById(SecurityUtil.getUserId());
|
||||
}
|
||||
|
||||
public Object getPrincipalProperty(String property) {
|
||||
Sys_user user = getLogonUser();
|
||||
if (user != null) {
|
||||
try {
|
||||
BeanInfo bi = Introspector.getBeanInfo(user.getClass());
|
||||
for (PropertyDescriptor pd : bi.getPropertyDescriptors()) {
|
||||
if (pd.getName().equals(property)) {
|
||||
return pd.getReadMethod().invoke(user, (Object[]) null);
|
||||
}
|
||||
}
|
||||
log.trace("Property [{}] not found in principal of type [{}]", property,
|
||||
user.getClass().getName());
|
||||
} catch (Exception e) {
|
||||
log.trace("Error reading property [{}] from principal of type [{}]", property,
|
||||
user.getClass().getName());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getLogonUserToJson() {
|
||||
Sys_user sys_user = sysUserService.getUserAndMenuById(SecurityUtil.getUserId());
|
||||
return Json.toJson(sys_user);
|
||||
}
|
||||
|
||||
public String getPrincipalPropertyToJson(String property) {
|
||||
Object principalProperty = getPrincipalProperty(property);
|
||||
return Json.toJson(principalProperty);
|
||||
}
|
||||
|
||||
public String getSessionId() {
|
||||
return StpUtil.getTokenValue();
|
||||
}
|
||||
|
||||
public Object getSubAppMenus(String appId) {
|
||||
List<Sys_menu> menus = sysUserService.getMenus(SecurityUtil.getUserId());
|
||||
List<Sys_menu> pcTreeMenus = SysMenuUtil.createTreeMenus(menus, appId);
|
||||
return pcTreeMenus;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.budwk.app.web.commons.auth.service;
|
||||
|
||||
import com.budwk.app.base.constant.RedisConstant;
|
||||
import com.budwk.app.base.exception.BaseException;
|
||||
import com.budwk.app.base.utils.RsaUtil;
|
||||
import com.wf.captcha.ArithmeticCaptcha;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.integration.jedis.RedisService;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.lang.random.R;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* @author wizzer@qq.com
|
||||
*/
|
||||
@IocBean
|
||||
@Slf4j
|
||||
public class ValidateService {
|
||||
@Inject
|
||||
private RedisService redisService;
|
||||
|
||||
/**
|
||||
* 获取验证码
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public NutMap getCaptcha() {
|
||||
String uuid = R.UU32();
|
||||
ArithmeticCaptcha captcha = new ArithmeticCaptcha(120, 40);
|
||||
captcha.getArithmeticString(); // 获取运算的公式:3+2=?
|
||||
String text = captcha.text();
|
||||
redisService.setex(RedisConstant.UCENTER_CAPTCHA + uuid, 180, text);
|
||||
return NutMap.NEW().addv("key", uuid).addv("codeUrl", captcha.toBase64());
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送短信验证码
|
||||
*
|
||||
* @param mobile 手机号码
|
||||
* @throws BaseException
|
||||
*/
|
||||
public void getSmsCode(String mobile) throws BaseException {
|
||||
String text = R.captchaNumber(4);
|
||||
String codeFromRedis = redisService.get(RedisConstant.UCENTER_SMSCODE + mobile + ":LOCK");
|
||||
if (Strings.isNotBlank(codeFromRedis)) {
|
||||
throw new BaseException("请1分钟之后再试");
|
||||
}
|
||||
// smsSendServer.sendCode(mobile, text);
|
||||
log.debug("sms code:::" + text);
|
||||
redisService.setex(RedisConstant.UCENTER_SMSCODE + mobile, 300, text);
|
||||
redisService.setex(RedisConstant.UCENTER_SMSCODE + mobile + ":LOCK", 60, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 核验验证码
|
||||
*
|
||||
* @param key 验证码的key
|
||||
* @param code 验证码的值
|
||||
* @throws BaseException
|
||||
*/
|
||||
public void checkCode(String key, String code) throws BaseException {
|
||||
String codeFromRedis = redisService.get(RedisConstant.UCENTER_CAPTCHA + key);
|
||||
|
||||
if (Strings.isBlank(code)) {
|
||||
throw new BaseException("请输入验证码");
|
||||
}
|
||||
if (Strings.isEmpty(codeFromRedis)) {
|
||||
throw new BaseException("验证码已过期");
|
||||
}
|
||||
if (!Strings.equalsIgnoreCase(code, codeFromRedis)) {
|
||||
throw new BaseException("验证码不正确");
|
||||
}
|
||||
redisService.del(RedisConstant.UCENTER_CAPTCHA + key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 核验短信验证码
|
||||
*
|
||||
* @param mobile 手机号码
|
||||
* @param code 验证码值
|
||||
* @throws BaseException
|
||||
*/
|
||||
public void checkSMSCode(String mobile, String code) throws BaseException {
|
||||
String codeFromRedis = redisService.get(RedisConstant.UCENTER_SMSCODE + mobile);
|
||||
|
||||
if (Strings.isBlank(code)) {
|
||||
throw new BaseException("请输入短信验证码");
|
||||
}
|
||||
if (Strings.isEmpty(codeFromRedis)) {
|
||||
throw new BaseException("短信验证码已过期");
|
||||
}
|
||||
if (!Strings.equalsIgnoreCase(code, codeFromRedis)) {
|
||||
throw new BaseException("短信验证码不正确");
|
||||
}
|
||||
redisService.del(RedisConstant.UCENTER_SMSCODE + mobile);
|
||||
}
|
||||
|
||||
public String decryptPwd(String keyId, String password) throws Exception {
|
||||
// 从 Redis 获取私钥
|
||||
String rsaKey = RedisConstant.RSA_KEY_PREFIX + keyId;
|
||||
String privateKeyStr = redisService.get(rsaKey);
|
||||
if (privateKeyStr == null) {
|
||||
throw new BaseException("公钥已过期,请刷新登录页面");
|
||||
}
|
||||
// 删除私钥(一次性使用,防重放)
|
||||
redisService.del(rsaKey);
|
||||
// 解码私钥
|
||||
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyStr);
|
||||
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
|
||||
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec);
|
||||
// 解密密码
|
||||
return RsaUtil.decrypt(password, privateKey);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.budwk.app.web.commons.auth.utils;
|
||||
|
||||
import cn.dev33.satoken.exception.NotRoleException;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author zzr
|
||||
* @name:AuthUtil
|
||||
* @Date 2024/8/6 14:48
|
||||
* @注释
|
||||
*/
|
||||
@Slf4j
|
||||
public class AuthUtil extends StpUtil {
|
||||
|
||||
|
||||
/**
|
||||
* 判断是否包含角色
|
||||
* @param roles
|
||||
* @return
|
||||
*/
|
||||
public static boolean hasRoleOr(String... roles) {
|
||||
try {
|
||||
stpLogic.checkRoleOr(roles);
|
||||
return true;
|
||||
} catch (NotRoleException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断是否角色是否都拥有
|
||||
* @param roles
|
||||
* @return
|
||||
*/
|
||||
public static boolean hasRoleAnd(String... roles) {
|
||||
try {
|
||||
stpLogic.checkRoleAnd(roles);
|
||||
return true;
|
||||
} catch (NotRoleException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.budwk.app.web.commons.auth.utils;
|
||||
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import org.nutz.lang.Strings;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author wizzer@qq.com
|
||||
*/
|
||||
public class SecurityUtil {
|
||||
|
||||
/**
|
||||
* 获取当前用户ID
|
||||
*/
|
||||
public static String getUserId() {
|
||||
return Strings.sNull(StpUtil.getLoginId(""));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户登录名
|
||||
*/
|
||||
public static String getUserLoginname() {
|
||||
return Strings.sNull(getSession().get("loginname"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户姓名
|
||||
*/
|
||||
public static String getUserUsername() {
|
||||
return Strings.sNull(getSession().get("username"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户单位ID
|
||||
*/
|
||||
public static String getUnitId() {
|
||||
return Strings.sNull(getSession().get("unitId"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户工会ID
|
||||
*/
|
||||
public static String getUnionId() {
|
||||
return Strings.sNull(getSession().get("unionId"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取当前用户工会小组ID
|
||||
*/
|
||||
public static String getUnionGroupId() {
|
||||
return Strings.sNull(getSession().get("unionGroupId"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户协会ID
|
||||
*/
|
||||
public static List<String> getClubIds() {
|
||||
String clubIds = getSession().get("clubIds").toString();
|
||||
return Arrays.stream(clubIds.split(",")).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户Session
|
||||
*/
|
||||
public static SaSession getSession() {
|
||||
return StpUtil.getSession(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package com.budwk.app.web.commons.base;
|
||||
|
||||
import cn.hutool.core.lang.ClassScanner;
|
||||
import com.budwk.app.base.annotation.DictEnum;
|
||||
import com.budwk.app.base.utils.EnumUtil;
|
||||
import com.budwk.app.sys.models.Sys_config;
|
||||
import com.budwk.app.sys.models.Sys_route;
|
||||
import com.budwk.app.sys.models.Sys_task;
|
||||
import com.budwk.app.sys.services.SysConfigService;
|
||||
import com.budwk.app.sys.services.SysRouteService;
|
||||
import com.budwk.app.sys.services.SysTaskService;
|
||||
import com.budwk.app.task.services.TaskPlatformService;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.ioc.impl.PropertiesProxy;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
@IocBean(create = "init")
|
||||
public class Globals {
|
||||
//项目路径
|
||||
public static String AppRoot = "";
|
||||
//项目目录
|
||||
public static String AppBase = "";
|
||||
//项目名称
|
||||
public static String AppName = "智慧工会";
|
||||
//项目LOGO
|
||||
public static String AppLogo = "";
|
||||
//项目域名
|
||||
public static String AppDomain = "http://127.0.0.1";
|
||||
//文件访问域名
|
||||
public static String AppFileDomain = "";
|
||||
//学校代码
|
||||
public static String SchoolCode = "OTHER";
|
||||
//系统自定义参数
|
||||
public static NutMap MyConfig = NutMap.NEW();
|
||||
//自定义路由
|
||||
public static NutMap RouteMap = NutMap.NEW();
|
||||
//微信map
|
||||
public static NutMap WxMap = NutMap.NEW();
|
||||
//枚举map
|
||||
public static Map<String, List<Map<String, Object>>> EnumMap = new HashMap<>();
|
||||
//是否开启单点登录
|
||||
public static boolean sso = false;
|
||||
@Inject
|
||||
private SysConfigService sysConfigService;
|
||||
@Inject
|
||||
private SysRouteService sysRouteService;
|
||||
@Inject
|
||||
private TaskPlatformService taskPlatformService;
|
||||
@Inject
|
||||
private SysTaskService sysTaskService;
|
||||
@Inject
|
||||
private PropertiesProxy conf;
|
||||
|
||||
public void init() {
|
||||
initSysConfig(sysConfigService);
|
||||
initRoute(sysRouteService);
|
||||
initTask(sysTaskService);
|
||||
initEnum();
|
||||
Globals.sso = conf.getBoolean("cas.enable", false);
|
||||
}
|
||||
|
||||
public void initTask(SysTaskService sysTaskService) {
|
||||
taskPlatformService.clear();
|
||||
List<Sys_task> taskList = sysTaskService.query();
|
||||
for (Sys_task sysTask : taskList) {
|
||||
try {
|
||||
if (!sysTask.isDisabled())//不存在则新建
|
||||
taskPlatformService.add(sysTask.getId(), sysTask.getId(), sysTask.getJobClass(), sysTask.getCron()
|
||||
, sysTask.getNote(), sysTask.getData());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void initSysConfig(SysConfigService sysConfigService) {
|
||||
Globals.MyConfig.clear();
|
||||
List<Sys_config> configList = sysConfigService.query();
|
||||
for (Sys_config sysConfig : configList) {
|
||||
switch (Strings.sNull(sysConfig.getConfigKey())) {
|
||||
case "AppName" -> Globals.AppName = sysConfig.getConfigValue();
|
||||
case "AppLogo" -> Globals.AppLogo = sysConfig.getConfigValue();
|
||||
case "AppDomain" -> Globals.AppDomain = sysConfig.getConfigValue();
|
||||
case "AppFileDomain" -> Globals.AppFileDomain = sysConfig.getConfigValue();
|
||||
default -> Globals.MyConfig.put(sysConfig.getConfigKey(), sysConfig.getConfigValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void initRoute(SysRouteService sysRouteService) {
|
||||
Globals.RouteMap.clear();
|
||||
List<Sys_route> routeList = sysRouteService.query(Cnd.where("disabled", "=", false));
|
||||
for (Sys_route route : routeList) {
|
||||
Globals.RouteMap.put(route.getUrl(), route);
|
||||
}
|
||||
}
|
||||
|
||||
public static void initWx() {
|
||||
Globals.WxMap.clear();
|
||||
}
|
||||
|
||||
public static void initEnum() {
|
||||
Globals.EnumMap.clear();
|
||||
Set<Class<?>> classes = ClassScanner.scanPackageByAnnotation("com.budwk.app", DictEnum.class);
|
||||
for (Class<?> aClass : classes) {
|
||||
List<Map<String, Object>> list = EnumUtil.transToList(aClass);
|
||||
Globals.EnumMap.put(aClass.getSimpleName(), list);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.budwk.app.web.commons.ext.beetl;
|
||||
|
||||
import org.beetl.core.Resource;
|
||||
import org.beetl.core.misc.BeetlUtil;
|
||||
import org.beetl.core.resource.ClasspathResource;
|
||||
import org.beetl.core.resource.ClasspathResourceLoader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class BeetlCustomResourceLoader extends ClasspathResourceLoader {
|
||||
|
||||
public Resource getResource(String key) {
|
||||
Resource resource = new ClasspathResource(key, this.getChildPath(super.getRoot(), key), this);
|
||||
return resource;
|
||||
}
|
||||
|
||||
public String getResourceId(Resource resource, String id) {
|
||||
// return resource == null ? id : BeetlUtil.getRelPath(resource.getId(), id);
|
||||
return getRelPath(resource.getId(), id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加判断相对路径
|
||||
* 光见鬼
|
||||
*/
|
||||
private String getRelPath(String siblings, String resourceId) {
|
||||
// 参数校验
|
||||
if (resourceId == null || resourceId.isEmpty()) {
|
||||
throw new RuntimeException("资源ID为空,参数错");
|
||||
}
|
||||
|
||||
// 如果是绝对路径,直接返回(以 / 或 \ 开头)
|
||||
if (resourceId.charAt(0) == '\\' || resourceId.charAt(0) == '/') {
|
||||
if (BeetlUtil.isOutsideOfRoot(resourceId)) {
|
||||
throw new RuntimeException("不能访问外部文件或者模板");
|
||||
}
|
||||
return resourceId;
|
||||
}
|
||||
|
||||
// 处理相对路径
|
||||
String baseDir = siblings;
|
||||
// 如果siblings是文件路径,获取其所在目录
|
||||
int lastSeparatorIndex = Math.max(siblings.lastIndexOf('/'), siblings.lastIndexOf('\\'));
|
||||
if (lastSeparatorIndex > 0) {
|
||||
baseDir = siblings.substring(0, lastSeparatorIndex + 1);
|
||||
}
|
||||
|
||||
// 分割路径
|
||||
String[] parts = resourceId.replace('\\', '/').split("/");
|
||||
List<String> baseParts = new ArrayList<>(
|
||||
Arrays.asList(baseDir.replace('\\', '/').split("/"))
|
||||
);
|
||||
baseParts.removeIf(String::isEmpty);
|
||||
|
||||
// 处理 ../ 和 ./
|
||||
for (String part : parts) {
|
||||
if ("..".equals(part)) {
|
||||
if (!baseParts.isEmpty()) {
|
||||
baseParts.remove(baseParts.size() - 1);
|
||||
}
|
||||
} else if (!".".equals(part) && !part.isEmpty()) {
|
||||
baseParts.add(part);
|
||||
}
|
||||
}
|
||||
|
||||
// 组合最终路径
|
||||
String result = "/" + String.join("/", baseParts);
|
||||
|
||||
// 检查是否访问外部文件
|
||||
if (BeetlUtil.isOutsideOfRoot(result)) {
|
||||
throw new RuntimeException("不能访问外部文件或者模板");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.budwk.app.web.commons.ext.beetl;
|
||||
|
||||
import org.beetl.core.Format;
|
||||
import org.nutz.lang.Strings;
|
||||
|
||||
/**
|
||||
* Created by wizzer on 2018/1/23.
|
||||
*/
|
||||
public class FileSizeFormat implements Format {
|
||||
public Object format(Object data, String pattern) {
|
||||
return Strings.formatSizeForReadBy1024(Long.valueOf(Strings.sNull(data)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.budwk.app.web.commons.ext.beetl;
|
||||
|
||||
import org.beetl.core.Format;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.nutz.lang.Strings;
|
||||
|
||||
/**
|
||||
* Created by wizzer on 2018/2/6.
|
||||
*/
|
||||
public class Html2TxtFormat implements Format {
|
||||
|
||||
public Object format(Object data, String pattern) {
|
||||
if (data == null) {
|
||||
return "";
|
||||
}
|
||||
Document document= Jsoup.parse(Strings.sNull(data));
|
||||
String s = document.text();
|
||||
if (pattern != null && s.length() > Integer.valueOf(pattern)) {
|
||||
return s.substring(0, Integer.valueOf(pattern));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.budwk.app.web.commons.ext.beetl;
|
||||
|
||||
/**
|
||||
* Created by wizzer on 2017/2/8.
|
||||
*/
|
||||
|
||||
import org.beetl.core.Format;
|
||||
import org.nutz.lang.Strings;
|
||||
|
||||
public class HtmlEscapeFormat implements Format {
|
||||
|
||||
public Object format(Object data, String pattern) {
|
||||
return Strings.escapeHtml(String.valueOf(data == null ? "" : data));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
package com.budwk.app.web.commons.ext.beetl;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.beetl.core.Resource;
|
||||
import org.beetl.core.Template;
|
||||
import org.beetl.core.exception.BeetlException;
|
||||
import org.beetl.core.tag.Tag;
|
||||
import org.nutz.lang.random.R;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* include Vue组件标签
|
||||
* 慎用。。。。
|
||||
*/
|
||||
@Slf4j
|
||||
public class IncludeVueTag extends Tag {
|
||||
private static final String SCRIPT_START = "<script>";
|
||||
private static final String SCRIPT_END = "</script>";
|
||||
private static final String TEMPLATE_START = "<template>";
|
||||
private static final String TEMPLATE_END = "</template>";
|
||||
private static final String STYLE_START = "<style>";
|
||||
private static final String STYLE_END = "</style>";
|
||||
|
||||
private static final Pattern NAME_PATTERN = Pattern.compile("name:\\s*['\"]([^'\"]+)['\"]");
|
||||
private static final Pattern EXPORT_PATTERN = Pattern.compile("export\\s+default\\s*[{]");
|
||||
|
||||
//缓存一下 避免每次都转换 虽然没什么耗时
|
||||
private static final ConcurrentHashMap<String, CacheEntry> COMPONENT_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
static class CacheEntry {
|
||||
final String content; // 编译后的内容
|
||||
final String fileHash; // 文件内容的哈希值
|
||||
|
||||
CacheEntry(String content, String fileHash) {
|
||||
this.content = content;
|
||||
this.fileHash = fileHash;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
try {
|
||||
String resourceId = getRelResourceId();
|
||||
String result = getCompiledComponent(resourceId);
|
||||
ctx.byteWriter.writeString(result);
|
||||
} catch (Exception e) {
|
||||
handleError("Failed to process Vue component", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getCompiledComponent(String resourceId) {
|
||||
// 读取文件内容
|
||||
String fileContent = readVueFile(resourceId);
|
||||
String currentHash = md5Hex(fileContent);
|
||||
|
||||
// 检查缓存
|
||||
// CacheEntry cached = COMPONENT_CACHE.get(resourceId);
|
||||
// if (cached != null && cached.fileHash.equals(currentHash)) {
|
||||
// return cached.content;
|
||||
// }
|
||||
|
||||
// 如果缓存不存在或文件已变化,重新编译
|
||||
String compiledContent = processVueContent(fileContent);
|
||||
COMPONENT_CACHE.put(resourceId, new CacheEntry(compiledContent, currentHash));
|
||||
return compiledContent;
|
||||
}
|
||||
|
||||
private String readVueFile(String resourceId) {
|
||||
Template t = gt.getTemplate(resourceId, ctx);
|
||||
t.binding(ctx.globalVar);
|
||||
return t.render();
|
||||
}
|
||||
|
||||
private String md5Hex(String input) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
byte[] bytes = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : bytes) {
|
||||
sb.append(String.format("%02x", b));
|
||||
}
|
||||
return sb.toString();
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to generate MD5", e);
|
||||
return String.valueOf(input.hashCode());
|
||||
}
|
||||
}
|
||||
|
||||
// 获取路径
|
||||
protected String getRelResourceId() {
|
||||
if (args == null || args.length == 0 || args[0] == null) {
|
||||
throw new RuntimeException("Vue component path is required");
|
||||
}
|
||||
Resource sibling = ctx.getResource();
|
||||
return gt.getResourceLoader().getResourceId(sibling, args[0].toString());
|
||||
}
|
||||
|
||||
private String processVueContent(String content) {
|
||||
try {
|
||||
String script = extractScript(content);
|
||||
String componentName = extractComponentName(script);
|
||||
|
||||
return generateJsComponent(
|
||||
extractTemplate(content),
|
||||
processScript(script, componentName),
|
||||
extractStyle(content),
|
||||
componentName
|
||||
);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to process Vue content", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String extractTemplate(String content) {
|
||||
String template = extractBetween(content, "<template>", "</template>");
|
||||
if (template.isEmpty()) {
|
||||
throw new RuntimeException("Template section is required in Vue component");
|
||||
}
|
||||
return template
|
||||
.replace("`", "\\`")
|
||||
.replace("${", "\\${");
|
||||
}
|
||||
|
||||
private String extractComponentName(String script) {
|
||||
Matcher matcher = NAME_PATTERN.matcher(script);
|
||||
if (matcher.find()) {
|
||||
return matcher.group(1);
|
||||
}
|
||||
// 如果没有找到名称 直接抛异常 为什么不写name呢
|
||||
String relResourceId = getRelResourceId();
|
||||
throw new BeetlException(BeetlException.ERROR, relResourceId + "没有name属性-----------");
|
||||
}
|
||||
|
||||
private String extractScript(String content) {
|
||||
String script = extractBetween(content, SCRIPT_START, SCRIPT_END);
|
||||
if (script.isEmpty()) {
|
||||
throw new RuntimeException("Script section is required in Vue component");
|
||||
}
|
||||
return script;
|
||||
}
|
||||
|
||||
private String processScript(String script, String componentName) {
|
||||
// 使用正则表达式替换 export default
|
||||
return EXPORT_PATTERN.matcher(script)
|
||||
.replaceFirst("const " + componentName + " = {");
|
||||
}
|
||||
|
||||
private String extractStyle(String content) {
|
||||
String style = extractBetween(content, STYLE_START, STYLE_END);
|
||||
return style.replace("`", "\\`");
|
||||
}
|
||||
|
||||
private String extractBetween(String content, String start, String end) {
|
||||
if (content == null || content.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
int startIndex = content.indexOf(start);
|
||||
if (startIndex == -1) {
|
||||
return "";
|
||||
}
|
||||
|
||||
int endIndex = content.indexOf(end, startIndex + start.length());
|
||||
if (endIndex == -1) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return content.substring(startIndex + start.length(), endIndex).trim();
|
||||
}
|
||||
|
||||
private String generateJsComponent(String template, String script, String style, String name) {
|
||||
return """
|
||||
<script>
|
||||
%s
|
||||
%s.template=`%s`;
|
||||
(function(){
|
||||
const styleId='vue-style-%s-%s';
|
||||
function addStyle() {
|
||||
if(!document.getElementById(styleId)) {
|
||||
const style=document.createElement('style');
|
||||
style.id=styleId;
|
||||
style.textContent=`%s`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
}
|
||||
// 立即添加样式
|
||||
addStyle();
|
||||
// 保存原始的生命周期方法
|
||||
const originalMounted = %s.mounted;
|
||||
const originalDestroyed = %s.destroyed;
|
||||
// 扩展 mounted 钩子,确保样式存在
|
||||
%s.mounted = function() {
|
||||
addStyle();
|
||||
if(originalMounted) originalMounted.call(this);
|
||||
};
|
||||
// 扩展 destroyed 钩子,检查是否还有其他实例在使用样式
|
||||
%s.destroyed = function() {
|
||||
if(originalDestroyed) originalDestroyed.call(this);
|
||||
// 检查是否还有其他实例在使用该组件
|
||||
setTimeout(() => {
|
||||
const instances = document.querySelectorAll('[data-component="%s"]');
|
||||
if(instances.length === 0) {
|
||||
const styleEl = document.getElementById(styleId);
|
||||
if(styleEl) document.head.removeChild(styleEl);
|
||||
}
|
||||
}, 0);
|
||||
};
|
||||
})();</script>
|
||||
""".formatted(
|
||||
script.trim(),
|
||||
name,
|
||||
template.trim().replaceAll("template-slot", "template"), // 将临时标签改回来
|
||||
name,
|
||||
R.UU32(),
|
||||
style.trim(),
|
||||
name, name, name, name, name
|
||||
);
|
||||
}
|
||||
|
||||
private void handleError(String message, Exception e) {
|
||||
log.error(message, e);
|
||||
try {
|
||||
ctx.byteWriter.writeString(
|
||||
String.format(
|
||||
"<script>console.error('%s: %s');</script>",
|
||||
message.replace("'", "\\'"),
|
||||
e.getMessage().replace("'", "\\'")
|
||||
)
|
||||
);
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException("Failed to write error message", ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.budwk.app.web.commons.ext.beetl;
|
||||
|
||||
import org.beetl.core.Format;
|
||||
import org.nutz.lang.Strings;
|
||||
|
||||
/**
|
||||
* Created by wizzer on 2018/2/6.
|
||||
*/
|
||||
public class StrlenFormat implements Format {
|
||||
|
||||
public Object format(Object data, String pattern) {
|
||||
if (data == null) {
|
||||
return "";
|
||||
}
|
||||
String s = Strings.sNull(data);
|
||||
if (pattern != null && s.length() > Integer.valueOf(pattern)) {
|
||||
return s.substring(0, Integer.valueOf(pattern));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.budwk.app.web.commons.ext.handler;
|
||||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.json.Json;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.log.Log;
|
||||
import org.nutz.log.Logs;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 错误页拦截器,登陆后台显示友好提示
|
||||
*/
|
||||
@IocBean
|
||||
public class WkErrorPageHandler extends ErrorPageErrorHandler {
|
||||
private static final Log log = Logs.get();
|
||||
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
if (response.getStatus() == 403 || response.getStatus() == 404 || response.getStatus() == 500) {
|
||||
try {
|
||||
if (isAjax(request)) {
|
||||
response.getWriter().write(Json.toJson(new NutMap("code", "-1").setv("msg", response.getStatus() + " error")));
|
||||
return;
|
||||
} else {
|
||||
request.setAttribute("original_request_uri", request.getRequestURI());
|
||||
RequestDispatcher rd = request.getRequestDispatcher("/platform/home/" + response.getStatus());
|
||||
rd.forward(request, response);
|
||||
return;
|
||||
}
|
||||
} catch (ServletException e) {
|
||||
log.error(e);
|
||||
}
|
||||
}
|
||||
super.handle(target, baseRequest, request, response);
|
||||
}
|
||||
|
||||
private boolean isAjax(ServletRequest req) {
|
||||
String value = ((HttpServletRequest) req).getHeader("X-Requested-With");
|
||||
return value != null && "XMLHttpRequest".equalsIgnoreCase(value.trim());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.budwk.app.web.commons.ext.pubsub;
|
||||
|
||||
import com.budwk.app.base.constant.RedisConstant;
|
||||
import com.budwk.app.sys.services.SysConfigService;
|
||||
import com.budwk.app.sys.services.SysRouteService;
|
||||
import com.budwk.app.web.commons.base.Globals;
|
||||
import org.nutz.integration.jedis.pubsub.PubSub;
|
||||
import org.nutz.integration.jedis.pubsub.PubSubService;
|
||||
import org.nutz.ioc.Ioc;
|
||||
import org.nutz.ioc.impl.PropertiesProxy;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.log.Log;
|
||||
import org.nutz.log.Logs;
|
||||
|
||||
/**
|
||||
* 订阅发布用于更新所有实例的 Globals变量
|
||||
*/
|
||||
@IocBean(create = "init")
|
||||
public class WebPubSub implements PubSub {
|
||||
private static final Log log = Logs.get();
|
||||
@Inject
|
||||
protected PubSubService pubSubService;
|
||||
@Inject
|
||||
protected SysConfigService sysConfigService;
|
||||
@Inject
|
||||
protected SysRouteService sysRouteService;
|
||||
|
||||
@Inject("refer:$ioc")
|
||||
protected Ioc ioc;
|
||||
|
||||
@Inject
|
||||
protected PropertiesProxy conf;
|
||||
|
||||
public void init() {
|
||||
pubSubService.reg(RedisConstant.PLATFORM_REDIS_PREFIX+"web:platform", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String channel, String message) {
|
||||
log.debug("WebPubSub onMessage::" + message);
|
||||
switch (message) {
|
||||
case "sys_config":
|
||||
Globals.initSysConfig(sysConfigService);
|
||||
break;
|
||||
case "sys_route":
|
||||
Globals.initRoute(sysRouteService);
|
||||
break;
|
||||
case "sys_wx":
|
||||
Globals.initWx();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
//package com.budwk.app.web.commons.ext.sms;
|
||||
//
|
||||
//import com.budwk.app.base.exception.BaseException;
|
||||
//import com.tencentcloudapi.common.Credential;
|
||||
//import com.tencentcloudapi.common.exception.TencentCloudSDKException;
|
||||
//import com.tencentcloudapi.common.profile.ClientProfile;
|
||||
//import com.tencentcloudapi.common.profile.HttpProfile;
|
||||
//import com.tencentcloudapi.sms.v20190711.SmsClient;
|
||||
//import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest;
|
||||
//import com.tencentcloudapi.sms.v20190711.models.SendSmsResponse;
|
||||
//import org.nutz.ioc.impl.PropertiesProxy;
|
||||
//import org.nutz.ioc.loader.annotation.Inject;
|
||||
//import org.nutz.ioc.loader.annotation.IocBean;
|
||||
//import org.nutz.log.Log;
|
||||
//import org.nutz.log.Logs;
|
||||
//
|
||||
///**
|
||||
// * 短信服务
|
||||
// *
|
||||
// * @author wizzer@qq.com
|
||||
// */
|
||||
//@IocBean
|
||||
//public class SmsService {
|
||||
// private static final Log log = Logs.get();
|
||||
// @Inject
|
||||
// private PropertiesProxy conf;
|
||||
//
|
||||
// /**
|
||||
// * 发送短信验证码
|
||||
// *
|
||||
// * @param mobile 手机号
|
||||
// * @param text 验证码
|
||||
// * @return true发送成功
|
||||
// * @throws BaseException
|
||||
// */
|
||||
// public boolean sendCode(String mobile, String text) throws BaseException {
|
||||
// try {
|
||||
// if (!conf.getBoolean("sms.enabled")) {
|
||||
// return true;
|
||||
// }
|
||||
// Credential cred = new Credential(conf.get("sms.tencent.secret-id"), conf.get("sms.tencent.secret-key"));
|
||||
//
|
||||
// HttpProfile httpProfile = new HttpProfile();
|
||||
// httpProfile.setEndpoint("sms.tencentcloudapi.com");
|
||||
//
|
||||
// ClientProfile clientProfile = new ClientProfile();
|
||||
// clientProfile.setHttpProfile(httpProfile);
|
||||
//
|
||||
// SmsClient client = new SmsClient(cred, "", clientProfile);
|
||||
//
|
||||
// SendSmsRequest req = new SendSmsRequest();
|
||||
// String[] phoneNumberSet1 = {"+86"+mobile};
|
||||
// req.setPhoneNumberSet(phoneNumberSet1);
|
||||
// String[] templateParamSet1 = {text};
|
||||
// req.setTemplateParamSet(templateParamSet1);
|
||||
// req.setTemplateID(conf.get("sms.tencent.tpl.code"));
|
||||
// req.setSmsSdkAppid(conf.get("sms.tencent.appid"));
|
||||
// req.setSign(conf.get("sms.tencent.sign"));
|
||||
// SendSmsResponse resp = client.SendSms(req);
|
||||
// log.debug(SendSmsResponse.toJsonString(resp));
|
||||
// return true;
|
||||
// } catch (TencentCloudSDKException tencentCloudSDKException) {
|
||||
// throw new BaseException(tencentCloudSDKException.getMessage());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 发送短信通知
|
||||
// *
|
||||
// * @param mobile 手机号码(最多200)
|
||||
// * @param param 模板参数值
|
||||
// * @return
|
||||
// * @throws BaseException
|
||||
// */
|
||||
// public boolean sendMsg(String[] mobile, String[] param) throws BaseException {
|
||||
// try {
|
||||
// if (!conf.getBoolean("sms.enabled")) {
|
||||
// return true;
|
||||
// }
|
||||
// Credential cred = new Credential(conf.get("sms.tencent.secret-id"), conf.get("sms.tencent.secret-key"));
|
||||
//
|
||||
// HttpProfile httpProfile = new HttpProfile();
|
||||
// httpProfile.setEndpoint("sms.tencentcloudapi.com");
|
||||
//
|
||||
// ClientProfile clientProfile = new ClientProfile();
|
||||
// clientProfile.setHttpProfile(httpProfile);
|
||||
//
|
||||
// SmsClient client = new SmsClient(cred, "", clientProfile);
|
||||
//
|
||||
// SendSmsRequest req = new SendSmsRequest();
|
||||
// req.setPhoneNumberSet(mobile);
|
||||
// req.setTemplateParamSet(param);
|
||||
// req.setTemplateID(conf.get("sms.tencent.tpl.msg"));
|
||||
// req.setSmsSdkAppid(conf.get("sms.tencent.appid"));
|
||||
// req.setSign(conf.get("sms.tencent.sign"));
|
||||
// SendSmsResponse resp = client.SendSms(req);
|
||||
// log.debug(SendSmsResponse.toJsonString(resp));
|
||||
// return true;
|
||||
// } catch (TencentCloudSDKException tencentCloudSDKException) {
|
||||
// throw new BaseException(tencentCloudSDKException.getMessage());
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.budwk.app.web.commons.ext.websocket;
|
||||
|
||||
import org.nutz.integration.jedis.JedisAgent;
|
||||
import org.nutz.log.Log;
|
||||
import org.nutz.log.Logs;
|
||||
import org.nutz.plugins.mvc.websocket.WsRoomProvider;
|
||||
import redis.clients.jedis.Jedis;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Redis聊天室实现
|
||||
*/
|
||||
public class WkJedisRoomProvider implements WsRoomProvider {
|
||||
private static final Log log = Logs.get();
|
||||
protected JedisAgent jedisAgent;
|
||||
protected int RedisKeySessionTTL;
|
||||
|
||||
public WkJedisRoomProvider(JedisAgent jedisAgent, int RedisKeySessionTTL) {
|
||||
this.jedisAgent = jedisAgent;
|
||||
this.RedisKeySessionTTL = RedisKeySessionTTL;
|
||||
}
|
||||
|
||||
public Set<String> wsids(String room) {
|
||||
try (Jedis jedis = jedisAgent.getResource()) {
|
||||
return jedis.smembers(room);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加入房间
|
||||
* @param room
|
||||
* @param wsid
|
||||
*/
|
||||
public void join(String room, String wsid) {
|
||||
try (Jedis jedis = jedisAgent.getResource()) {
|
||||
jedis.sadd(room, wsid);
|
||||
jedis.expire(room,RedisKeySessionTTL);//每次加入的时候时间有效期重置?
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 离开房间
|
||||
* @param room
|
||||
* @param wsid
|
||||
*/
|
||||
public void left(String room, String wsid) {
|
||||
try (Jedis jedis = jedisAgent.getResource()) {
|
||||
jedis.srem(room, wsid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.budwk.app.web.commons.ext.websocket;
|
||||
|
||||
import com.budwk.app.base.constant.RedisConstant;
|
||||
import org.nutz.integration.jedis.JedisAgent;
|
||||
import org.nutz.integration.jedis.pubsub.PubSub;
|
||||
import org.nutz.integration.jedis.pubsub.PubSubService;
|
||||
import org.nutz.ioc.Ioc;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.log.Log;
|
||||
import org.nutz.log.Logs;
|
||||
import org.nutz.plugins.mvc.websocket.AbstractWsEndpoint;
|
||||
import org.nutz.plugins.mvc.websocket.NutWsConfigurator;
|
||||
import org.nutz.plugins.mvc.websocket.WsHandler;
|
||||
import redis.clients.jedis.*;
|
||||
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ServerEndpoint(value = "/websocket", configurator = NutWsConfigurator.class)
|
||||
@IocBean(create = "init") // 使用NutWsConfigurator的必备条件
|
||||
public class WkWebSocket extends AbstractWsEndpoint implements PubSub {
|
||||
protected static final Log log = Logs.get();
|
||||
@Inject
|
||||
protected PubSubService pubSubService;
|
||||
@Inject
|
||||
protected JedisAgent jedisAgent;
|
||||
@Inject("refer:$ioc")
|
||||
protected Ioc ioc;
|
||||
@Inject("java:$conf.getInt('security.timeout')")
|
||||
private int REDIS_KEY_SESSION_TTL;
|
||||
|
||||
public WsHandler createHandler(Session session, EndpointConfig config) {
|
||||
return ioc.get(WkWsHandler.class);
|
||||
}
|
||||
|
||||
public void init() {
|
||||
roomProvider = new WkJedisRoomProvider(jedisAgent, REDIS_KEY_SESSION_TTL);
|
||||
if (jedisAgent.isClusterMode()) {
|
||||
JedisCluster jedisCluster = jedisAgent.getJedisClusterWrapper().getJedisCluster();
|
||||
List<String> keys=new ArrayList<>();
|
||||
for (JedisPool pool : jedisCluster.getClusterNodes().values()) {
|
||||
try (Jedis jedis = pool.getResource()) {
|
||||
ScanParams match = new ScanParams().match(RedisConstant.REDIS_KEY_WSROOM + "*");
|
||||
ScanResult<String> scan = null;
|
||||
do {
|
||||
scan = jedis.scan(scan == null ? ScanParams.SCAN_POINTER_START : scan.getStringCursor(), match);
|
||||
keys.addAll(scan.getResult());
|
||||
|
||||
} while (!scan.isCompleteIteration());
|
||||
}
|
||||
}
|
||||
try (Jedis jedis = jedisAgent.getResource()) {
|
||||
for (String key : keys) {
|
||||
switch (jedis.type(key)) {
|
||||
case "none":
|
||||
break;
|
||||
case "set":
|
||||
break;
|
||||
default:
|
||||
jedis.del(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try (Jedis jedis = jedisAgent.getResource()) {
|
||||
ScanParams match = new ScanParams().match(RedisConstant.REDIS_KEY_WSROOM + "*");
|
||||
ScanResult<String> scan = null;
|
||||
do {
|
||||
scan = jedis.scan(scan == null ? ScanParams.SCAN_POINTER_START : scan.getStringCursor(), match);
|
||||
for (String key : scan.getResult()) {
|
||||
switch (jedis.type(key)) {
|
||||
case "none":
|
||||
break;
|
||||
case "set":
|
||||
break;
|
||||
default:
|
||||
jedis.del(key);
|
||||
}
|
||||
}
|
||||
} while (!scan.isCompleteIteration());
|
||||
}
|
||||
}
|
||||
pubSubService.reg(RedisConstant.REDIS_KEY_WSROOM + "*", this);
|
||||
}
|
||||
|
||||
|
||||
public void onMessage(String channel, String message) {
|
||||
if (log.isDebugEnabled())
|
||||
log.debugf("GET PubSub channel=%s msg=%s", channel, message);
|
||||
each(channel, (index, session, length) -> session.getAsyncRemote().sendText(message));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.budwk.app.web.commons.ext.websocket;
|
||||
|
||||
import com.budwk.app.base.constant.RedisConstant;
|
||||
import org.nutz.integration.jedis.RedisService;
|
||||
import org.nutz.integration.jedis.pubsub.PubSubService;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import redis.clients.jedis.ScanParams;
|
||||
import redis.clients.jedis.ScanResult;
|
||||
|
||||
@IocBean
|
||||
public class WkWebSocketUtil {
|
||||
|
||||
@Inject
|
||||
private PubSubService pubSubService;
|
||||
@Inject
|
||||
private RedisService redisService;
|
||||
|
||||
public void fire(String loginName, String message) {
|
||||
ScanParams match = new ScanParams().match(RedisConstant.REDIS_KEY_WSROOM + loginName + ":*");
|
||||
ScanResult<String> scan = null;
|
||||
do {
|
||||
scan = redisService.scan(scan == null ? ScanParams.SCAN_POINTER_START : scan.getStringCursor(), match);
|
||||
for (String key : scan.getResult()) {
|
||||
// NutMap data = NutMap.NEW().addv("action", "h5-scan-code-signature").addv("value", url).addv("id", id);
|
||||
pubSubService.fire(key, message);
|
||||
}
|
||||
} while (!scan.isCompleteIteration());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.budwk.app.web.commons.ext.websocket;
|
||||
|
||||
import com.budwk.app.base.constant.RedisConstant;
|
||||
import com.budwk.app.sys.services.SysMsgService;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.log.Log;
|
||||
import org.nutz.log.Logs;
|
||||
import org.nutz.plugins.mvc.websocket.handler.SimpleWsHandler;
|
||||
|
||||
@IocBean
|
||||
public class WkWsHandler extends SimpleWsHandler {
|
||||
private static final Log log = Logs.get();
|
||||
@Inject
|
||||
private SysMsgService sysMsgService;
|
||||
|
||||
@Override
|
||||
public void join(NutMap req) {
|
||||
join(req.getString("room"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void left(NutMap req) {
|
||||
left(req.getString("room"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void join(String room) {
|
||||
if (!Strings.isBlank(room)) {
|
||||
room = RedisConstant.REDIS_KEY_WSROOM + room;
|
||||
log.debugf("session(id=%s) join room(name=%s)", session.getId(), room);
|
||||
roomProvider.join(room, session.getId());
|
||||
//获取用户的未读消息数量及列表
|
||||
sysMsgService.getMsg(room.split(":")[2]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void left(String room) {
|
||||
if (!Strings.isBlank(room)) {
|
||||
room = RedisConstant.REDIS_KEY_WSROOM + room;
|
||||
log.debugf("session(id=%s) left room(name=%s)", session.getId(), room);
|
||||
roomProvider.left(room, session.getId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取消息
|
||||
* @param req
|
||||
*/
|
||||
public void getMessage(NutMap req) {
|
||||
String room = req.getString("room");
|
||||
if (!Strings.isBlank(room)) {
|
||||
room = RedisConstant.REDIS_KEY_WSROOM + room;
|
||||
log.debugf("session(id=%s) getMessage room(name=%s)", session.getId(), room);
|
||||
//获取用户的未读消息数量及列表
|
||||
sysMsgService.getMsg(room.split(":")[2]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void depose() {
|
||||
//覆盖原生写法,因为room= loginname + httpSessionId 和聊天室的机制不一样,不覆盖的话功能会异常
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.budwk.app.web.commons.filter;
|
||||
|
||||
import com.budwk.app.sys.models.Sys_route;
|
||||
import com.budwk.app.web.commons.base.Globals;
|
||||
import org.nutz.lang.Strings;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by Wizzer on 2016/7/31.
|
||||
*/
|
||||
public class RouteFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest req, ServletResponse res,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
HttpServletRequest req2 = (HttpServletRequest) req;
|
||||
HttpServletResponse res2 = (HttpServletResponse) res;
|
||||
res2.setCharacterEncoding("utf-8");
|
||||
req2.setCharacterEncoding("utf-8");
|
||||
Sys_route route = Globals.RouteMap.getAs(Strings.sNull(req2.getRequestURI()).replace(Globals.AppBase, ""), Sys_route.class);
|
||||
if (route != null) {
|
||||
if ("show".equals(route.getType())) {
|
||||
res2.sendRedirect(route.getToUrl());
|
||||
} else {
|
||||
req2.getRequestDispatcher(route.getToUrl()).forward(req2, res2);
|
||||
}
|
||||
} else chain.doFilter(req2, res2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig arg0) throws ServletException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.budwk.app.web.commons.filter;
|
||||
|
||||
import org.nutz.boot.AppContext;
|
||||
import org.nutz.boot.starter.WebFilterFace;
|
||||
import org.nutz.ioc.Ioc;
|
||||
import org.nutz.ioc.impl.PropertiesProxy;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.Filter;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@IocBean
|
||||
public class RouteFilterStarter implements WebFilterFace {
|
||||
|
||||
|
||||
@Inject("refer:$ioc")
|
||||
protected Ioc ioc;
|
||||
|
||||
@Inject
|
||||
protected PropertiesProxy conf;
|
||||
|
||||
@Inject
|
||||
protected AppContext appContext;
|
||||
|
||||
public String getName() {
|
||||
return "routeFilterStarter";
|
||||
}
|
||||
|
||||
public String getPathSpec() {
|
||||
return "/*";
|
||||
}
|
||||
|
||||
public EnumSet<DispatcherType> getDispatches() {
|
||||
return EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE);
|
||||
}
|
||||
|
||||
@IocBean(name="routeFilter")
|
||||
public RouteFilter createRouteFilter() {
|
||||
return new RouteFilter();
|
||||
}
|
||||
|
||||
public Filter getFilter() {
|
||||
return ioc.get(RouteFilter.class, "routeFilter");
|
||||
}
|
||||
|
||||
public Map<String, String> getInitParameters() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return 11;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
//package com.budwk.app.web.commons.filter.cas;
|
||||
//
|
||||
//import cn.hutool.core.util.ArrayUtil;
|
||||
//import cn.hutool.core.util.StrUtil;
|
||||
//import com.budwk.app.web.commons.base.Globals;
|
||||
//import org.jasig.cas.client.authentication.DefaultGatewayResolverImpl;
|
||||
//import org.jasig.cas.client.authentication.GatewayResolver;
|
||||
//import org.jasig.cas.client.util.AbstractCasFilter;
|
||||
//import org.jasig.cas.client.util.CommonUtils;
|
||||
//import org.jasig.cas.client.util.ReflectUtils;
|
||||
//import org.jasig.cas.client.validation.Assertion;
|
||||
//
|
||||
//import javax.servlet.*;
|
||||
//import javax.servlet.http.Cookie;
|
||||
//import javax.servlet.http.HttpServletRequest;
|
||||
//import javax.servlet.http.HttpServletResponse;
|
||||
//import javax.servlet.http.HttpSession;
|
||||
//import java.io.IOException;
|
||||
//import java.net.URLEncoder;
|
||||
//import java.nio.charset.StandardCharsets;
|
||||
//import java.util.HashMap;
|
||||
//import java.util.Map;
|
||||
//
|
||||
//public class CasAuthenticationFilter extends AbstractCasFilter {
|
||||
//
|
||||
// /**
|
||||
// * The URL to the CAS Server login.
|
||||
// */
|
||||
// private String casServerLoginUrl;
|
||||
//
|
||||
// /**
|
||||
// * Whether to send the renew request or not.
|
||||
// */
|
||||
// private boolean renew = false;
|
||||
//
|
||||
// /**
|
||||
// * Whether to send the gateway request or not.
|
||||
// */
|
||||
// private boolean gateway = false;
|
||||
//
|
||||
// /**
|
||||
// * The method used by the CAS server to send the user back to the application.
|
||||
// */
|
||||
// private String method;
|
||||
//
|
||||
// private GatewayResolver gatewayStorage = new DefaultGatewayResolverImpl();
|
||||
//
|
||||
// private AuthenticationRedirectStrategy authenticationRedirectStrategy = new DefaultAuthenticationRedirectStrategy();
|
||||
//
|
||||
// private UrlPatternMatcherStrategy ignoreUrlPatternMatcherStrategyClass = null;
|
||||
//
|
||||
// private static final Map<String, Class<? extends UrlPatternMatcherStrategy>> PATTERN_MATCHER_TYPES =
|
||||
// new HashMap<String, Class<? extends UrlPatternMatcherStrategy>>();
|
||||
//
|
||||
// static {
|
||||
// PATTERN_MATCHER_TYPES.put("CONTAINS", ContainsPatternUrlPatternMatcherStrategy.class);
|
||||
// PATTERN_MATCHER_TYPES.put("REGEX", RegexUrlPatternMatcherStrategy.class);
|
||||
// PATTERN_MATCHER_TYPES.put("FULL_REGEX", EntireRegionRegexUrlPatternMatcherStrategy.class);
|
||||
// PATTERN_MATCHER_TYPES.put("EXACT", ExactUrlPatternMatcherStrategy.class);
|
||||
// }
|
||||
//
|
||||
// public CasAuthenticationFilter() {
|
||||
// this(Protocol.CAS2);
|
||||
// }
|
||||
//
|
||||
// protected CasAuthenticationFilter(final Protocol protocol) {
|
||||
// super(protocol);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected void initInternal(final FilterConfig filterConfig) throws ServletException {
|
||||
// if (!isIgnoreInitConfiguration()) {
|
||||
// super.initInternal(filterConfig);
|
||||
//
|
||||
// final String loginUrl = getString(ConfigurationKeys.CAS_SERVER_LOGIN_URL);
|
||||
// if (loginUrl != null) {
|
||||
// setCasServerLoginUrl(loginUrl);
|
||||
// } else {
|
||||
// setCasServerUrlPrefix(getString(ConfigurationKeys.CAS_SERVER_URL_PREFIX));
|
||||
// }
|
||||
//
|
||||
// setRenew(getBoolean(ConfigurationKeys.RENEW));
|
||||
// setGateway(getBoolean(ConfigurationKeys.GATEWAY));
|
||||
// setMethod(getString(ConfigurationKeys.METHOD));
|
||||
//
|
||||
// final String ignorePattern = getString(ConfigurationKeys.IGNORE_PATTERN);
|
||||
// final String ignoreUrlPatternType = getString(ConfigurationKeys.IGNORE_URL_PATTERN_TYPE);
|
||||
//
|
||||
// if (ignorePattern != null) {
|
||||
// final Class<? extends UrlPatternMatcherStrategy> ignoreUrlMatcherClass = PATTERN_MATCHER_TYPES.get(ignoreUrlPatternType);
|
||||
// if (ignoreUrlMatcherClass != null) {
|
||||
// this.ignoreUrlPatternMatcherStrategyClass = ReflectUtils.newInstance(ignoreUrlMatcherClass.getName());
|
||||
// } else {
|
||||
// try {
|
||||
// logger.trace("Assuming {} is a qualified class name...", ignoreUrlPatternType);
|
||||
// this.ignoreUrlPatternMatcherStrategyClass = ReflectUtils.newInstance(ignoreUrlPatternType);
|
||||
// } catch (final IllegalArgumentException e) {
|
||||
// logger.error("Could not instantiate class [{}]", ignoreUrlPatternType, e);
|
||||
// }
|
||||
// }
|
||||
// if (this.ignoreUrlPatternMatcherStrategyClass != null) {
|
||||
// this.ignoreUrlPatternMatcherStrategyClass.setPattern(ignorePattern);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// final Class<? extends GatewayResolver> gatewayStorageClass = getClass(ConfigurationKeys.GATEWAY_STORAGE_CLASS);
|
||||
//
|
||||
// if (gatewayStorageClass != null) {
|
||||
// setGatewayStorage(ReflectUtils.newInstance(gatewayStorageClass));
|
||||
// }
|
||||
//
|
||||
// final Class<? extends AuthenticationRedirectStrategy> authenticationRedirectStrategyClass = getClass(ConfigurationKeys.AUTHENTICATION_REDIRECT_STRATEGY_CLASS);
|
||||
//
|
||||
// if (authenticationRedirectStrategyClass != null) {
|
||||
// this.authenticationRedirectStrategy = ReflectUtils.newInstance(authenticationRedirectStrategyClass);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void init() {
|
||||
// super.init();
|
||||
//
|
||||
// final String message = String.format(
|
||||
// "one of %s and %s must not be null.",
|
||||
// ConfigurationKeys.CAS_SERVER_LOGIN_URL.getName(),
|
||||
// ConfigurationKeys.CAS_SERVER_URL_PREFIX.getName());
|
||||
//
|
||||
// CommonUtils.assertNotNull(this.casServerLoginUrl, message);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
|
||||
// final FilterChain filterChain) throws IOException, ServletException {
|
||||
//
|
||||
// final HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
// final HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
//
|
||||
// boolean isLocalLogin = false;
|
||||
//
|
||||
// Cookie[] cookies = request.getCookies();
|
||||
// if(ArrayUtil.isNotEmpty(cookies)){
|
||||
// for (Cookie cookie : cookies) {
|
||||
// String name = cookie.getName();
|
||||
// if("saToken".equals(name) && StrUtil.isNotBlank(cookie.getValue())){
|
||||
// isLocalLogin = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//// logger.debug("本地登录状态:" + isLogin);
|
||||
// if (isLocalLogin) {
|
||||
// logger.debug("本地已登录登录,无需cas认证");
|
||||
// filterChain.doFilter(request, response);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// if (isRequestUrlExcluded(request)) {
|
||||
// logger.debug("Request is ignored.");
|
||||
// filterChain.doFilter(request, response);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// final HttpSession session = request.getSession(false);
|
||||
// final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;
|
||||
//
|
||||
// if (assertion != null) {
|
||||
// filterChain.doFilter(request, response);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// final String serviceUrl = constructServiceUrl(request, response);
|
||||
// final String ticket = retrieveTicketFromRequest(request);
|
||||
// final boolean wasGatewayed = this.gateway && this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
|
||||
//
|
||||
// if (CommonUtils.isNotBlank(ticket) || wasGatewayed) {
|
||||
// filterChain.doFilter(request, response);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// final String modifiedServiceUrl;
|
||||
//
|
||||
// logger.debug("no ticket and no assertion found");
|
||||
// if (this.gateway) {
|
||||
// logger.debug("setting gateway attribute in session");
|
||||
// modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
|
||||
// } else {
|
||||
// modifiedServiceUrl = serviceUrl;
|
||||
// }
|
||||
//
|
||||
// logger.debug("Constructed service url: {}", modifiedServiceUrl);
|
||||
//
|
||||
// //回调到统一入口
|
||||
// String cas_callback = Globals.AppDomain + "/platform/login/doCasLogin";
|
||||
//
|
||||
// String finalModifiedServiceUrl = cas_callback + "?redirect=" + URLEncoder.encode(modifiedServiceUrl, StandardCharsets.UTF_8);
|
||||
//// String finalModifiedServiceUrl = cas_callback;
|
||||
//
|
||||
// final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl,
|
||||
// getProtocol().getServiceParameterName(), finalModifiedServiceUrl, this.renew, this.gateway, this.method);
|
||||
//
|
||||
// logger.debug("redirecting to \"{}\"", urlToRedirectTo);
|
||||
// this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo);
|
||||
//
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public final void setRenew(final boolean renew) {
|
||||
// this.renew = renew;
|
||||
// }
|
||||
//
|
||||
// public final void setGateway(final boolean gateway) {
|
||||
// this.gateway = gateway;
|
||||
// }
|
||||
//
|
||||
// public void setMethod(final String method) {
|
||||
// this.method = method;
|
||||
// }
|
||||
//
|
||||
// public final void setCasServerUrlPrefix(final String casServerUrlPrefix) {
|
||||
// setCasServerLoginUrl(CommonUtils.addTrailingSlash(casServerUrlPrefix) + "login");
|
||||
// }
|
||||
//
|
||||
// public final void setCasServerLoginUrl(final String casServerLoginUrl) {
|
||||
// this.casServerLoginUrl = casServerLoginUrl;
|
||||
// }
|
||||
//
|
||||
// public final void setGatewayStorage(final GatewayResolver gatewayStorage) {
|
||||
// this.gatewayStorage = gatewayStorage;
|
||||
// }
|
||||
//
|
||||
// private boolean isRequestUrlExcluded(final HttpServletRequest request) {
|
||||
// if (this.ignoreUrlPatternMatcherStrategyClass == null) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// String requestURI = request.getRequestURI();
|
||||
// String queryString = request.getQueryString();
|
||||
//
|
||||
// if (queryString != null) {
|
||||
// return this.ignoreUrlPatternMatcherStrategyClass.matches(requestURI + "?" + queryString);
|
||||
// } else {
|
||||
// return this.ignoreUrlPatternMatcherStrategyClass.matches(requestURI);
|
||||
// }
|
||||
//
|
||||
//
|
||||
//// final StringBuffer urlBuffer = request.getRequestURL();
|
||||
//// if (request.getQueryString() != null) {
|
||||
//// urlBuffer.append("?").append(request.getQueryString());
|
||||
//// }
|
||||
//// final String requestUri = urlBuffer.toString();
|
||||
//// return this.ignoreUrlPatternMatcherStrategyClass.matches(requestUri);
|
||||
// }
|
||||
//
|
||||
// public final void setIgnoreUrlPatternMatcherStrategyClass(
|
||||
// final UrlPatternMatcherStrategy ignoreUrlPatternMatcherStrategyClass) {
|
||||
// this.ignoreUrlPatternMatcherStrategyClass = ignoreUrlPatternMatcherStrategyClass;
|
||||
// }
|
||||
//
|
||||
//}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
//package com.budwk.app.web.commons.filter.cas;
|
||||
//
|
||||
//import org.jasig.cas.client.authentication.AuthenticationFilter;
|
||||
//import org.jasig.cas.client.authentication.UrlPatternMatcherStrategy;
|
||||
//import org.nutz.boot.AppContext;
|
||||
//import org.nutz.boot.starter.WebFilterFace;
|
||||
//import org.nutz.ioc.Ioc;
|
||||
//import org.nutz.ioc.impl.PropertiesProxy;
|
||||
//import org.nutz.ioc.loader.annotation.Inject;
|
||||
//import org.nutz.ioc.loader.annotation.IocBean;
|
||||
//
|
||||
//import javax.servlet.DispatcherType;
|
||||
//import javax.servlet.Filter;
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.EnumSet;
|
||||
//import java.util.Map;
|
||||
//
|
||||
//@IocBean
|
||||
//public class CasAuthenticationFilterStarter implements WebFilterFace {
|
||||
//
|
||||
// @Inject("refer:$ioc")
|
||||
// protected Ioc ioc;
|
||||
//
|
||||
// @Inject
|
||||
// protected PropertiesProxy conf;
|
||||
//
|
||||
// @Inject
|
||||
// protected AppContext appContext;
|
||||
//
|
||||
// @Override
|
||||
// public String getName() {
|
||||
// return "CasAuthenticationFilterStarter";
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String getPathSpec() {
|
||||
// return "/*";
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public EnumSet<DispatcherType> getDispatches() {
|
||||
// return EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE);
|
||||
// }
|
||||
//
|
||||
// @IocBean(name = "casFilter")
|
||||
// public CasAuthenticationFilter createCasFilter() {
|
||||
// CasAuthenticationFilter authenticationFilter = new CasAuthenticationFilter();
|
||||
// authenticationFilter.setCasServerUrlPrefix(conf.get("cas.server-url-prefix"));
|
||||
// authenticationFilter.setCasServerLoginUrl(conf.get("cas.server-login-url"));
|
||||
// authenticationFilter.setServerName(conf.get("cas.client-host-url"));
|
||||
// authenticationFilter.setIgnoreInitConfiguration(true);
|
||||
//
|
||||
// ArrayList<String> urls = new ArrayList<>() {{
|
||||
// add("/platform/home/404");
|
||||
// add("/platform/home/403");
|
||||
// add("/platform/home/500");
|
||||
// add("/platform/home/unknownAccountError");
|
||||
// add("/platform/login");
|
||||
// add("/platform/login/doLogin");
|
||||
// add("/platform/login/doCasLogin");
|
||||
// add("/platform/login/logout");
|
||||
// add("/error");
|
||||
// add("/assets");
|
||||
// }};
|
||||
// UrlPatternMatcherStrategy urlPatternMatcherStrategy = new SimpleUrlPatternMatcherStrategy(urls);
|
||||
// authenticationFilter.setIgnoreUrlPatternMatcherStrategyClass(urlPatternMatcherStrategy);
|
||||
// return authenticationFilter;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Filter getFilter() {
|
||||
// boolean enable = conf.getBoolean("cas.enable", false);
|
||||
// if (!enable) {
|
||||
// return null;
|
||||
// }
|
||||
// return ioc.get(AuthenticationFilter.class, "casFilter");
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Map<String, String> getInitParameters() {
|
||||
// return Map.of();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public int getOrder() {
|
||||
// return 14;
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,83 @@
|
||||
//package com.budwk.app.web.commons.filter.cas;
|
||||
//
|
||||
//import org.jasig.cas.client.session.SingleSignOutFilter;
|
||||
//import org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter;
|
||||
//import org.nutz.boot.starter.WebFilterFace;
|
||||
//import org.nutz.boot.starter.impl.WebFilterReg;
|
||||
//import org.nutz.ioc.impl.PropertiesProxy;
|
||||
//import org.nutz.ioc.loader.annotation.Inject;
|
||||
//import org.nutz.ioc.loader.annotation.IocBean;
|
||||
//
|
||||
//import javax.servlet.DispatcherType;
|
||||
//import java.util.HashMap;
|
||||
//import java.util.HashSet;
|
||||
//
|
||||
//@IocBean(create = "init")
|
||||
//public class CasFilterConfig {
|
||||
//
|
||||
// @Inject
|
||||
// protected PropertiesProxy conf;
|
||||
//
|
||||
// public void init(){
|
||||
// createCasAuthenticationFilter();
|
||||
// createCasTicketValidationFilter();
|
||||
// createCasSingleSignOutFilter();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 单点退出过滤器
|
||||
// */
|
||||
// public WebFilterFace createCasSingleSignOutFilter() {
|
||||
// SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
|
||||
//
|
||||
// WebFilterReg reg = new WebFilterReg();
|
||||
// reg.setFilter(singleSignOutFilter);
|
||||
// reg.setName("casSingleSignOutFilter");
|
||||
// reg.setPathSpecs(new String[]{"/*"});
|
||||
// reg.setOrder(12);
|
||||
// return reg;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 单点认证过滤器
|
||||
// */
|
||||
// public WebFilterFace createCasAuthenticationFilter() {
|
||||
// CasAuthenticationFilter authenticationFilter = new CasAuthenticationFilter();
|
||||
// authenticationFilter.setCasServerUrlPrefix(conf.get("cas.server-url-prefix"));
|
||||
// authenticationFilter.setCasServerLoginUrl(conf.get("cas.server-login-url"));
|
||||
// authenticationFilter.setServerName(conf.get("cas.client-host-url"));
|
||||
// authenticationFilter.setIgnoreInitConfiguration(true);
|
||||
//
|
||||
// WebFilterReg reg = new WebFilterReg();
|
||||
// reg.setFilter(authenticationFilter);
|
||||
// reg.setName("casAuthenticationFilter");
|
||||
// reg.setPathSpecs(new String[]{"/*"});
|
||||
// reg.setInitParameters(null);
|
||||
// reg.setDispatcheTypes(new HashSet<>(){{
|
||||
// add(DispatcherType.REQUEST);
|
||||
// add(DispatcherType.FORWARD);
|
||||
// }});
|
||||
// reg.setOrder(14);
|
||||
// return reg;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 票据认证过滤器
|
||||
// */
|
||||
// public WebFilterFace createCasTicketValidationFilter() {
|
||||
// Cas20ProxyReceivingTicketValidationFilter ticketValidationFilter = new Cas20ProxyReceivingTicketValidationFilter();
|
||||
//
|
||||
// HashMap<String, String> initParams = new HashMap<>();
|
||||
// initParams.put("casServerUrlPrefix", conf.get("cas.server-url-prefix"));
|
||||
// initParams.put("serverName", conf.get("cas.client-host-url"));
|
||||
//
|
||||
// WebFilterReg reg = new WebFilterReg();
|
||||
// reg.setFilter(ticketValidationFilter);
|
||||
// reg.setName("casTicketValidationFilter");
|
||||
// reg.setPathSpecs(new String[]{"/*"});
|
||||
// reg.setInitParameters(initParams);
|
||||
// reg.setOrder(13);
|
||||
// return reg;
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.budwk.app.web.commons.filter.cas;
|
||||
|
||||
import org.jasig.cas.client.session.SingleSignOutFilter;
|
||||
import org.nutz.boot.starter.WebFilterFace;
|
||||
import org.nutz.ioc.impl.PropertiesProxy;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.Filter;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@IocBean
|
||||
public class CasSingleSignOutFilterStarter implements WebFilterFace {
|
||||
|
||||
@Inject
|
||||
protected PropertiesProxy conf;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "casSingleSignOutFilterStarter";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPathSpec() {
|
||||
return "/*";
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<DispatcherType> getDispatches() {
|
||||
return EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter getFilter() {
|
||||
boolean enable = conf.getBoolean("cas.enable", false);
|
||||
if (!enable) {
|
||||
return null;
|
||||
}
|
||||
SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
|
||||
return singleSignOutFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getInitParameters() {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("casServerUrlPrefix",conf.get("cas.server-url-prefix"));
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 12;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.budwk.app.web.commons.filter.cas;
|
||||
|
||||
import org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter;
|
||||
import org.nutz.boot.AppContext;
|
||||
import org.nutz.boot.starter.WebFilterFace;
|
||||
import org.nutz.ioc.Ioc;
|
||||
import org.nutz.ioc.impl.PropertiesProxy;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.Filter;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@IocBean
|
||||
public class CasTicketFilterStarter implements WebFilterFace {
|
||||
|
||||
@Inject("refer:$ioc")
|
||||
protected Ioc ioc;
|
||||
|
||||
@Inject
|
||||
protected PropertiesProxy conf;
|
||||
|
||||
@Inject
|
||||
protected AppContext appContext;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "casTicketFilterStarter";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPathSpec() {
|
||||
return "/*";
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<DispatcherType> getDispatches() {
|
||||
return EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE);
|
||||
}
|
||||
|
||||
@IocBean(name="casTicketFilter")
|
||||
public Cas20ProxyReceivingTicketValidationFilter ticketValidationFilter() {
|
||||
Cas20ProxyReceivingTicketValidationFilter filter = new Cas20ProxyReceivingTicketValidationFilter();
|
||||
return filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter getFilter() {
|
||||
boolean enable = conf.getBoolean("cas.enable", false);
|
||||
if (!enable) {
|
||||
return null;
|
||||
}
|
||||
return ioc.get(Cas20ProxyReceivingTicketValidationFilter.class, "casTicketFilter");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getInitParameters() {
|
||||
HashMap<String, String> initParams = new HashMap<>();
|
||||
initParams.put("casServerUrlPrefix", conf.get("cas.server-url-prefix"));
|
||||
initParams.put("serverName", conf.get("cas.client-host-url"));
|
||||
//initParams.put("service", conf.get("cas.client-host-url")+conf.get("cas.client-call-back-url"));
|
||||
return initParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 13;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.budwk.app.web.commons.filter.cas;
|
||||
|
||||
import org.jasig.cas.client.session.SingleSignOutHttpSessionListener;
|
||||
import org.nutz.boot.starter.WebEventListenerFace;
|
||||
import org.nutz.ioc.impl.PropertiesProxy;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
@IocBean
|
||||
public class CasWebEventListenerFace implements WebEventListenerFace {
|
||||
|
||||
@Inject
|
||||
protected PropertiesProxy conf;
|
||||
|
||||
@Override
|
||||
public EventListener getEventListener() {
|
||||
if (conf.getBoolean("cas.enable", false)){
|
||||
return null;
|
||||
}
|
||||
return new SingleSignOutHttpSessionListener();
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
//package com.budwk.app.web.commons.filter.cas;
|
||||
//
|
||||
//import org.jasig.cas.client.authentication.UrlPatternMatcherStrategy;
|
||||
//
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.List;
|
||||
//
|
||||
//
|
||||
//public class SimpleUrlPatternMatcherStrategy implements UrlPatternMatcherStrategy {
|
||||
//
|
||||
// private List<String> urls = new ArrayList<>();
|
||||
//
|
||||
// public SimpleUrlPatternMatcherStrategy(List<String> urls){
|
||||
// this.urls = urls;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean matches(String url) {
|
||||
// boolean b = urls.stream().anyMatch(url::contains);
|
||||
// return b;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void setPattern(String pattern) {
|
||||
//
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.budwk.app.web.commons.proc;
|
||||
|
||||
import org.nutz.mvc.ActionContext;
|
||||
import org.nutz.mvc.impl.processor.AbstractProcessor;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* @ClassName CspProcessor
|
||||
* @Author JyuHsin
|
||||
* @Date 2025/12/19 9:58
|
||||
* @Version 1.0
|
||||
* @Description TODO
|
||||
*/
|
||||
public class CspProcessor extends AbstractProcessor {
|
||||
|
||||
public void process(ActionContext ac) throws Throwable {
|
||||
// 1. 生成 nonce
|
||||
String nonce = Base64.getEncoder().encodeToString(
|
||||
java.security.SecureRandom.getInstanceStrong().generateSeed(16)
|
||||
);
|
||||
|
||||
// 2. 存入 request,供 Beetl 使用
|
||||
ac.getRequest().setAttribute("cspNonce", nonce);
|
||||
|
||||
// 3. 设置 CSP 头
|
||||
String csp = "default-src 'self'; " +
|
||||
"script-src 'self' 'unsafe-eval' 'nonce-" + nonce + "' https:; " +
|
||||
"worker-src 'self' blob:;" +
|
||||
"style-src * 'unsafe-inline' data:; " +
|
||||
"img-src 'self' data: http: https:; " +
|
||||
"font-src * data: https:; " +
|
||||
"connect-src 'self' https: webpack:; " +
|
||||
"frame-ancestors 'self'; " +
|
||||
"object-src 'self';";
|
||||
|
||||
ac.getResponse().setHeader("Content-Security-Policy", csp);
|
||||
|
||||
doNext(ac);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.budwk.app.web.commons.proc;
|
||||
|
||||
import com.budwk.app.base.utils.DateUtil;
|
||||
import com.budwk.app.base.utils.StringUtil;
|
||||
import com.budwk.app.web.commons.auth.service.AuthService;
|
||||
import com.budwk.app.web.commons.base.Globals;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.mvc.ActionContext;
|
||||
import org.nutz.mvc.ActionInfo;
|
||||
import org.nutz.mvc.Mvcs;
|
||||
import org.nutz.mvc.NutConfig;
|
||||
import org.nutz.mvc.impl.processor.AbstractProcessor;
|
||||
|
||||
/**
|
||||
* Created by wizzer on 2016/6/22.
|
||||
*/
|
||||
public class GlobalsSettingProcessor extends AbstractProcessor {
|
||||
private static DateUtil dateUtil;
|
||||
private static StringUtil stringUtil;
|
||||
private static AuthService authService;
|
||||
|
||||
public void init(NutConfig config, ActionInfo ai) throws Throwable {
|
||||
if (dateUtil == null) {
|
||||
dateUtil = new DateUtil();
|
||||
}
|
||||
if (stringUtil == null) {
|
||||
stringUtil = new StringUtil();
|
||||
}
|
||||
if (authService == null) {
|
||||
authService = config.getIoc().get(AuthService.class);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void process(ActionContext ac) throws Throwable {
|
||||
ac.getRequest().setAttribute("AppRoot", Globals.AppRoot);
|
||||
ac.getRequest().setAttribute("AppBase", Globals.AppBase);
|
||||
ac.getRequest().setAttribute("AppName", Globals.AppName);
|
||||
ac.getRequest().setAttribute("AppLogo", Globals.AppLogo);
|
||||
ac.getRequest().setAttribute("AppDomain", Globals.AppDomain);
|
||||
ac.getRequest().setAttribute("AppFileDomain", Globals.AppFileDomain);
|
||||
ac.getRequest().setAttribute("config", Globals.MyConfig);
|
||||
ac.getRequest().setAttribute("auth", authService);
|
||||
ac.getRequest().setAttribute("date", dateUtil);
|
||||
ac.getRequest().setAttribute("string", stringUtil);
|
||||
// 如果url中有语言属性则设置
|
||||
String lang = ac.getRequest().getParameter("lang");
|
||||
if (!Strings.isEmpty(lang)) {
|
||||
Mvcs.setLocalizationKey(lang);
|
||||
} else {
|
||||
// Mvcs.getLocalizationKey() 1.r.56 版本是null,所以要做两次判断, 1.r.57已修复为默认值 Nutz:Fix issue 1072
|
||||
lang = Strings.isBlank(Mvcs.getLocalizationKey()) ? Mvcs.getDefaultLocalizationKey() : Mvcs.getLocalizationKey();
|
||||
}
|
||||
ac.getRequest().setAttribute("lang", lang);
|
||||
doNext(ac);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.budwk.app.web.commons.proc;
|
||||
|
||||
import org.nutz.lang.Stopwatch;
|
||||
import org.nutz.log.Log;
|
||||
import org.nutz.log.Logs;
|
||||
import org.nutz.mvc.ActionContext;
|
||||
import org.nutz.mvc.impl.processor.AbstractProcessor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Created by Wizzer.cn on 2015/7/2.
|
||||
*/
|
||||
public class LogTimeProcessor extends AbstractProcessor {
|
||||
|
||||
private static final Log log = Logs.get();
|
||||
|
||||
public void process(ActionContext ac) throws Throwable {
|
||||
if (log.isDebugEnabled()) {
|
||||
Stopwatch sw = Stopwatch.begin();
|
||||
try {
|
||||
doNext(ac);
|
||||
} finally {
|
||||
sw.stop();
|
||||
HttpServletRequest req = ac.getRequest();
|
||||
log.debugf("[%-4s]URI=%s %sms", req.getMethod(), req.getRequestURI(), sw.getDuration());
|
||||
}
|
||||
} else {
|
||||
doNext(ac);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.budwk.app.web.commons.proc;
|
||||
|
||||
import com.budwk.app.base.exception.MethodArgumentNotValidException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.mvc.ActionContext;
|
||||
import org.nutz.mvc.impl.processor.AbstractProcessor;
|
||||
|
||||
import javax.validation.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* jug 自定义接口参数校验
|
||||
* 官方的很鸡肋 手搓
|
||||
* 使用方法:@Valid 注解 + validation-api包下面的注解即可
|
||||
* <p>
|
||||
* 重点!!!
|
||||
* 只能校验对象 基本数据类型不可以 也不要在基本数据类型上加这个注解 会报错的。。
|
||||
*/
|
||||
@Slf4j
|
||||
public class ParamValidationProcessor extends AbstractProcessor {
|
||||
|
||||
// protected ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
|
||||
|
||||
@Override
|
||||
public void process(ActionContext ac) throws Throwable {
|
||||
// Validator validator = factory.getValidator();
|
||||
// Method method = ac.getMethod();
|
||||
// Object[] methodArgs = ac.getMethodArgs();
|
||||
// Parameter[] parameters = method.getParameters();
|
||||
// for (int i = 0; i < parameters.length; i++) {
|
||||
// Parameter parameter = parameters[i];
|
||||
// boolean hasValidAnnotation = parameter.isAnnotationPresent(Valid.class);
|
||||
// if (hasValidAnnotation) {
|
||||
// Object argValue = methodArgs[i];
|
||||
// if (argValue == null) {
|
||||
// throw new MethodArgumentNotValidException(parameter.getName() + "不能为null");
|
||||
// }
|
||||
//
|
||||
// Set<ConstraintViolation<Object>> violations = validator.validate(argValue);
|
||||
// if (!violations.isEmpty()) {
|
||||
// String errMsg = violations.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(","));
|
||||
// throw new MethodArgumentNotValidException(errMsg);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
doNext(ac);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,328 @@
|
||||
package com.budwk.app.web.commons.proc;
|
||||
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.exception.NotPermissionException;
|
||||
import cn.dev33.satoken.exception.NotRoleException;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.http.useragent.UserAgent;
|
||||
import cn.hutool.http.useragent.UserAgentUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.budwk.app.base.constant.RedisConstant;
|
||||
import com.budwk.app.base.enums.BrowserPlatform;
|
||||
import com.budwk.app.base.exception.BaseException;
|
||||
import com.budwk.app.base.exception.MethodArgumentNotValidException;
|
||||
import com.budwk.app.base.exception.UnknownAccountException;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.result.ResultCode;
|
||||
import com.budwk.app.base.utils.WebUtil;
|
||||
import com.budwk.app.web.commons.base.Globals;
|
||||
import org.jasig.cas.client.util.AbstractCasFilter;
|
||||
import org.jasig.cas.client.validation.Assertion;
|
||||
import org.nutz.castor.FailToCastObjectException;
|
||||
import org.nutz.dao.DaoException;
|
||||
import org.nutz.integration.jedis.RedisService;
|
||||
import org.nutz.ioc.IocException;
|
||||
import org.nutz.ioc.ObjectLoadException;
|
||||
import org.nutz.ioc.impl.PropertiesProxy;
|
||||
import org.nutz.log.Log;
|
||||
import org.nutz.log.Logs;
|
||||
import org.nutz.mvc.ActionContext;
|
||||
import org.nutz.mvc.ActionInfo;
|
||||
import org.nutz.mvc.Mvcs;
|
||||
import org.nutz.mvc.NutConfig;
|
||||
import org.nutz.mvc.impl.processor.ViewProcessor;
|
||||
import org.nutz.mvc.upload.UploadUnsupportedFileNameException;
|
||||
import org.nutz.mvc.view.ForwardView;
|
||||
import org.nutz.mvc.view.ServerRedirectView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class WkFailProcessor extends ViewProcessor {
|
||||
|
||||
private static final Log log = Logs.get();
|
||||
private String errorUri = "/platform/home/500";
|
||||
private String localLoginUri = "/platform/login";
|
||||
private String error403Uri = "/platform/home/403";
|
||||
private String errorUnknownAccountUri = "/platform/home/unknownAccountError";
|
||||
private static PropertiesProxy propertiesProxy;
|
||||
private static RedisService redisService;
|
||||
|
||||
@Override
|
||||
public void init(NutConfig config, ActionInfo ai) throws Throwable {
|
||||
view = evalView(config, ai, ai.getFailView());
|
||||
propertiesProxy = config.getIoc().get(PropertiesProxy.class, "conf");
|
||||
redisService = config.getIoc().get(RedisService.class);
|
||||
}
|
||||
|
||||
public void process(ActionContext ac) throws Throwable {
|
||||
if (log.isWarnEnabled()) {
|
||||
String uri = Mvcs.getRequestPath(ac.getRequest());
|
||||
log.warn(String.format("Error@%s :", uri), ac.getError());
|
||||
}
|
||||
Throwable e = ac.getError();
|
||||
// 捕获Ioc异常
|
||||
if (e instanceof IocException || e instanceof ObjectLoadException) {
|
||||
if (WebUtil.isAjax(ac.getRequest())) {
|
||||
WebUtil.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(ResultCode.IOC_ERROR.getCode(), !log.isDebugEnabled() ? ResultCode.IOC_ERROR.getMsg() : e.getMessage()));
|
||||
} else {
|
||||
ac.getRequest().setAttribute("original_request_uri", ac.getRequest().getRequestURI());
|
||||
ac.getRequest().setAttribute("error_message", Mvcs.getMessage(ac.getRequest(), ResultCode.IOC_ERROR.getMsg()));
|
||||
new ForwardView(errorUri).render(ac.getRequest(), ac.getResponse(), null);
|
||||
}
|
||||
return;
|
||||
} else if (e instanceof DaoException) {
|
||||
if (WebUtil.isAjax(ac.getRequest())) {
|
||||
// WebUtil.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(ResultCode.DAO_ERROR.getCode(), !log.isDebugEnabled() ? ResultCode.DAO_ERROR.getMsg() : e.getMessage()));
|
||||
WebUtil.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(ResultCode.DAO_ERROR.getCode(), ResultCode.DAO_ERROR.getMsg()));
|
||||
} else {
|
||||
ac.getRequest().setAttribute("original_request_uri", ac.getRequest().getRequestURI());
|
||||
ac.getRequest().setAttribute("error_message", Mvcs.getMessage(ac.getRequest(), ResultCode.DAO_ERROR.getMsg()));
|
||||
new ForwardView(errorUri).render(ac.getRequest(), ac.getResponse(), null);
|
||||
}
|
||||
return;
|
||||
} else if (e instanceof FailToCastObjectException) { // 捕获类型转换异常
|
||||
if (WebUtil.isAjax(ac.getRequest())) {
|
||||
WebUtil.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(ResultCode.PARAM_ERROR.getCode(), !log.isDebugEnabled() ? ResultCode.PARAM_ERROR.getMsg() : e.getMessage()));
|
||||
} else {
|
||||
ac.getRequest().setAttribute("original_request_uri", ac.getRequest().getRequestURI());
|
||||
ac.getRequest().setAttribute("error_message", Mvcs.getMessage(ac.getRequest(), ResultCode.PARAM_ERROR.getMsg()));
|
||||
new ForwardView(errorUri).render(ac.getRequest(), ac.getResponse(), null);
|
||||
}
|
||||
return;
|
||||
} else if (e instanceof UnknownAccountException) {
|
||||
new ServerRedirectView(Globals.AppDomain + errorUnknownAccountUri).render(ac.getRequest(), ac.getResponse(), null);
|
||||
} else if (e instanceof NotLoginException) { // 如果是未登录异常
|
||||
if (WebUtil.isAjax(ac.getRequest())) {
|
||||
WebUtil.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(e.getMessage()));
|
||||
} else {
|
||||
ac.getRequest().setAttribute("original_request_uri", ac.getRequest().getRequestURI());
|
||||
ac.getRequest().setAttribute("error_message", Mvcs.getMessage(ac.getRequest(), e.getMessage()));
|
||||
notLoginRedirect(ac.getRequest(), ac.getResponse());
|
||||
}
|
||||
return;
|
||||
} else if (e instanceof NotRoleException) { // 如果是角色异常
|
||||
if (WebUtil.isAjax(ac.getRequest())) {
|
||||
NotRoleException ee = (NotRoleException) e;
|
||||
WebUtil.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(ResultCode.USER_NOT_ROLE.getCode(), ResultCode.USER_NOT_ROLE.getMsg() + ": " + ee.getRole()));
|
||||
} else {
|
||||
ac.getRequest().setAttribute("original_request_uri", ac.getRequest().getRequestURI());
|
||||
ac.getRequest().setAttribute("error_message", Mvcs.getMessage(ac.getRequest(), ResultCode.USER_NOT_ROLE.getMsg()));
|
||||
new ForwardView(error403Uri).render(ac.getRequest(), ac.getResponse(), null);
|
||||
}
|
||||
return;
|
||||
} else if (e instanceof NotPermissionException) { // 如果是权限异常
|
||||
if (WebUtil.isAjax(ac.getRequest())) {
|
||||
NotPermissionException ee = (NotPermissionException) e;
|
||||
WebUtil.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(ResultCode.USER_NOT_PERMISSION.getCode(), ResultCode.USER_NOT_PERMISSION.getMsg() + ": " + ee.getCode()));
|
||||
} else {
|
||||
ac.getRequest().setAttribute("original_request_uri", ac.getRequest().getRequestURI());
|
||||
ac.getRequest().setAttribute("error_message", Mvcs.getMessage(ac.getRequest(), ResultCode.USER_NOT_PERMISSION.getMsg()));
|
||||
new ForwardView(error403Uri).render(ac.getRequest(), ac.getResponse(), null);
|
||||
}
|
||||
return;
|
||||
} else if (e instanceof MethodArgumentNotValidException) { //参数校验异常
|
||||
WebUtil.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(ResultCode.PARAM_VALID_ERROR.getCode(), e.getMessage()));
|
||||
return;
|
||||
} else if (e instanceof UploadUnsupportedFileNameException) {
|
||||
WebUtil.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(-1, "不支持该类型文件上传"));
|
||||
return;
|
||||
} else if (e instanceof BaseException) {
|
||||
if (WebUtil.isAjax(ac.getRequest())) {
|
||||
// WebUtil.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(ResultCode.FAILURE.getCode(), !log.isDebugEnabled() ? ResultCode.FAILURE.getMsg() : e.getMessage()));
|
||||
WebUtil.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(ResultCode.FAILURE.getCode(), e.getMessage()));
|
||||
} else {
|
||||
ac.getRequest().setAttribute("original_request_uri", ac.getRequest().getRequestURI());
|
||||
ac.getRequest().setAttribute("error_message", Mvcs.getMessage(ac.getRequest(), ResultCode.FAILURE.getMsg()));
|
||||
// new ForwardView(errorUri).render(ac.getRequest(), ac.getResponse(), null);
|
||||
}
|
||||
return;
|
||||
} else if (e instanceof RuntimeException) {
|
||||
if (WebUtil.isAjax(ac.getRequest())) {
|
||||
WebUtil.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(ResultCode.SERVER_ERROR.getCode(), !log.isDebugEnabled() ? ResultCode.SERVER_ERROR.getMsg() : e.getMessage()));
|
||||
} else {
|
||||
ac.getRequest().setAttribute("original_request_uri", ac.getRequest().getRequestURI());
|
||||
ac.getRequest().setAttribute("error_message", Mvcs.getMessage(ac.getRequest(), ResultCode.SERVER_ERROR.getMsg()));
|
||||
// new ForwardView(errorUri).render(ac.getRequest(), ac.getResponse(), null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
super.process(ac);
|
||||
}
|
||||
|
||||
/**
|
||||
* 未登录重定向
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @throws Throwable
|
||||
*/
|
||||
private void notLoginRedirect(HttpServletRequest request, HttpServletResponse response) throws Throwable {
|
||||
Assertion assertion = (Assertion) request.getSession().getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);
|
||||
if (assertion != null && assertion.getPrincipal() != null) {
|
||||
// //判断cas里面是否有用户名 那么造成的原因就是系统中没他的信息
|
||||
// //就是cas已经认证了 但是本地系统没有认证
|
||||
// String name = assertion.getPrincipal().getName();
|
||||
// log.error("未登录用户名:" + name);
|
||||
// new ServerRedirectView(Globals.AppDomain + errorUnknownAccountUri).render(request, response, null);
|
||||
|
||||
|
||||
// return;
|
||||
}
|
||||
|
||||
String requestURI = request.getRequestURI();
|
||||
String query = request.getQueryString();
|
||||
String redirect;
|
||||
if (StrUtil.isNotBlank(query)) {
|
||||
redirect = URLEncoder.encode(requestURI + "?" + query, StandardCharsets.UTF_8);
|
||||
} else {
|
||||
redirect = URLEncoder.encode(requestURI, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
//获取浏览器平台
|
||||
BrowserPlatform browserPlatform = getBrowserPlatform(request);
|
||||
|
||||
if (Globals.sso) {
|
||||
//1.判断是否为企业微信浏览器并且对接了企业微信
|
||||
if (browserPlatform == BrowserPlatform.QI_YE_WEI_XIN && propertiesProxy.getBoolean("wxwork.enable", false)) {
|
||||
//进行企业微信授权
|
||||
// String token = getWxWorkToken();
|
||||
// if (StrUtil.isNotBlank(token)) {
|
||||
// //跳转到企业微信授权地址
|
||||
// new ServerRedirectView(buildWxWorkOauth2Url()).render(request, response, null);
|
||||
// } else {
|
||||
// //跳转到错误页 别问我为啥错了 我也不知道 首先去检查配置文件里的参数有没有写对
|
||||
//// new ServerRedirectView(Globals.AppDomain + errorUri).render(request, response, null);
|
||||
// //跳转到cas登录页
|
||||
// String callBackUrl = propertiesProxy.get("cas.client-host-url") + propertiesProxy.get("cas.client-call-back-url") + "?redirect=" + redirect;
|
||||
// String authUrl = propertiesProxy.get("cas.qi-wx-server-login-url") + "?service=" + URLEncoder.encode(callBackUrl, StandardCharsets.UTF_8);
|
||||
// new ServerRedirectView(authUrl).render(request, response, null);
|
||||
// }
|
||||
|
||||
// 武汉城市职业学院 跳转到企业微信cas登录页
|
||||
String callBackUrl = propertiesProxy.get("wecom.wecom-client-host-url") + propertiesProxy.get("wecom.wecom-client-call-back-url") + "?redirect=" + redirect;
|
||||
String authUrl = propertiesProxy.get("wecom.wecom-server-login-url") + "?service=" + URLEncoder.encode(callBackUrl, StandardCharsets.UTF_8);
|
||||
log.info("auth:"+authUrl);
|
||||
new ServerRedirectView(authUrl).render(request, response, null);
|
||||
} else if (browserPlatform == BrowserPlatform.WEI_XIN && propertiesProxy.getBoolean("wx.enable", false)) {
|
||||
//进行微信公众号授权
|
||||
//跳转到微信授权页
|
||||
new ServerRedirectView(buildWxOauth2Url(redirect)).render(request, response, null);
|
||||
} else {
|
||||
//跳转到cas登录页
|
||||
String callBackUrl = propertiesProxy.get("cas.client-host-url") + propertiesProxy.get("cas.client-call-back-url") + "?redirect=" + redirect;
|
||||
String authUrl = propertiesProxy.get("cas.server-login-url") + "?service=" + URLEncoder.encode(callBackUrl, StandardCharsets.UTF_8);
|
||||
log.info("auth:"+authUrl);
|
||||
new ServerRedirectView(authUrl).render(request, response, null);
|
||||
}
|
||||
} else {
|
||||
//跳转到本地登录页
|
||||
new ServerRedirectView(Globals.AppDomain + localLoginUri + "?redirect=" + redirect).render(request, response, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断浏览器平台
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
private BrowserPlatform getBrowserPlatform(HttpServletRequest request) {
|
||||
String uaStr = request.getHeader("User-Agent");
|
||||
UserAgent ua = UserAgentUtil.parse(uaStr);
|
||||
if (ua.isMobile()) {
|
||||
if (uaStr.contains("MicroMessenger") && uaStr.contains("wxwork")) {
|
||||
return BrowserPlatform.QI_YE_WEI_XIN;
|
||||
}
|
||||
if (uaStr.contains("MicroMessenger")) {
|
||||
return BrowserPlatform.WEI_XIN;
|
||||
}
|
||||
return BrowserPlatform.H5_WEB;
|
||||
} else {
|
||||
return BrowserPlatform.PC_WEB;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取企业微信token
|
||||
*/
|
||||
private String getWxWorkToken() {
|
||||
String token = redisService.get(RedisConstant.REDIS_KEY_WX_WORK_TOKEN);
|
||||
if (StrUtil.isNotBlank(token)) {
|
||||
return token;
|
||||
}
|
||||
String appId = propertiesProxy.get("wxwork.corpId");
|
||||
String secret = propertiesProxy.get("wxwork.corpSecret");
|
||||
String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=ID&corpsecret=SECRET".replace("ID", appId)
|
||||
.replace("SECRET", secret);
|
||||
String response = HttpUtil.get(url);
|
||||
JSONObject jsonObject = JSONUtil.parseObj(response);
|
||||
if (jsonObject.getInt("errcode") == 0) {
|
||||
//官方提示:企业微信可能会出于运营需要,提前使access_token失效,开发者应实现access_token失效时重新获取的逻辑。
|
||||
redisService.setex(RedisConstant.REDIS_KEY_WX_WORK_TOKEN, 7000, jsonObject.getStr("access_token"));
|
||||
return jsonObject.getStr("access_token");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建企业微信oauth2授权url
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String buildWxWorkOauth2Url() {
|
||||
String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&state=STATE&agentid=AGENTID#wechat_redirect";
|
||||
url = url.replace("CORPID", propertiesProxy.get("wxwork.corpId"));
|
||||
url = url.replace("REDIRECT_URI", URLEncoder.encode(Globals.AppDomain + propertiesProxy.get("wxwork.redirectUri"), StandardCharsets.UTF_8));
|
||||
url = url.replace("AGENTID", propertiesProxy.get("wxwork.agentId"));
|
||||
return url;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取微信token
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String getWxToken() {
|
||||
String token = redisService.get(RedisConstant.REDIS_KEY_WX_TOKEN);
|
||||
if (StrUtil.isNotBlank(token)) {
|
||||
return token;
|
||||
}
|
||||
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
|
||||
String appID = propertiesProxy.get("wx.appID");
|
||||
String appSecret = propertiesProxy.get("wx.appSecret");
|
||||
assert appID != null;
|
||||
assert appSecret != null;
|
||||
url = url.replace("APPID", appID);
|
||||
url = url.replace("APPSECRET", appSecret);
|
||||
String response = HttpUtil.get(url);
|
||||
JSONObject jsonObject = JSONUtil.parseObj(response);
|
||||
if (jsonObject.getInt("errcode") == 0) {
|
||||
redisService.setex(RedisConstant.REDIS_KEY_WX_TOKEN, 7000, jsonObject.getStr("access_token"));
|
||||
return jsonObject.getStr("access_token");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建微信oauth2授权url
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String buildWxOauth2Url(String redirect) {
|
||||
String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
|
||||
url = url.replace("APPID", propertiesProxy.get("wx.appID"));
|
||||
url = url.replace("SCOPE", "snsapi_base");
|
||||
String wxRedirect = Globals.AppDomain + propertiesProxy.get("wx.redirectUri") + "?redirect=" + redirect;
|
||||
url = url.replace("REDIRECT_URI", URLEncoder.encode(wxRedirect, StandardCharsets.UTF_8));
|
||||
return url;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
package com.budwk.app.web.commons.proc;
|
||||
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.WebUtil;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.nutz.ioc.impl.PropertiesProxy;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.log.Log;
|
||||
import org.nutz.log.Logs;
|
||||
import org.nutz.mvc.ActionContext;
|
||||
import org.nutz.mvc.ActionInfo;
|
||||
import org.nutz.mvc.Mvcs;
|
||||
import org.nutz.mvc.NutConfig;
|
||||
import org.nutz.mvc.impl.processor.AbstractProcessor;
|
||||
import org.nutz.mvc.view.ForwardView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* SQL XSS拦截
|
||||
*/
|
||||
public class XssSqlFilterProcessor extends AbstractProcessor {
|
||||
|
||||
private static final Log log = Logs.get();
|
||||
protected String lerrorUri = "/error/403.html";
|
||||
private PropertiesProxy conf;
|
||||
private List<String> ignoreList;
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private static final Set<String> SQL_KEYWORDS = new HashSet<>(Arrays.asList(
|
||||
"select", "update", "delete", "insert", "truncate",
|
||||
"drop", "execute", "exec", "declare", "union",
|
||||
"create", "alter", "database", "table", "varchar",
|
||||
"extractvalue", "concat", "benchmark", "sleep", "delay",
|
||||
"waitfor", "pg_sleep", "information_schema", "sysobjects",
|
||||
"load_file", "outfile", "dumpfile"
|
||||
));
|
||||
|
||||
//合法字段
|
||||
private static final Set<String> ALLOWED_ORDER_FIELDS = new HashSet<>(Arrays.asList(
|
||||
"createdat", "updatedat"
|
||||
));
|
||||
|
||||
|
||||
@Override
|
||||
public void init(NutConfig config, ActionInfo ai) throws Throwable {
|
||||
try {
|
||||
conf = config.getIoc().get(org.nutz.ioc.impl.PropertiesProxy.class, "conf");
|
||||
ignoreList = Arrays.asList(Strings.splitIgnoreBlank(conf.get("xsssql.ignore.urls", "")));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void process(ActionContext ac) throws Throwable {
|
||||
// if (checkUrl(ac) && checkParams(ac)) {
|
||||
// if (WebUtil.isAjax(ac.getRequest())) {
|
||||
// ac.getResponse().addHeader("loginStatus", "paramsDenied");
|
||||
// WebUtil.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(Mvcs.getMessage(ac.getRequest(), "system.paramserror")));
|
||||
// } else {
|
||||
// new ForwardView(lerrorUri).render(ac.getRequest(), ac.getResponse(), Mvcs.getMessage(ac.getRequest(), "system.paramserror"));
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
doNext(ac);
|
||||
}
|
||||
|
||||
private boolean checkUrl(ActionContext ac) {
|
||||
String path = ac.getPath();
|
||||
return !ignoreList.contains(path);
|
||||
}
|
||||
|
||||
protected boolean checkParams(ActionContext ac) {
|
||||
HttpServletRequest req = ac.getRequest();
|
||||
|
||||
String pageOrderName = req.getParameter("pageOrderName");
|
||||
if (pageOrderName != null && ALLOWED_ORDER_FIELDS.contains(pageOrderName.toLowerCase())) {
|
||||
// 如果是预定义的排序字段,直接放行
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Iterator<String[]> values = req.getParameterMap().values().iterator();// 获取所有的表单参数
|
||||
Iterator<String[]> values2 = req.getParameterMap().values().iterator();// 因为是游标所以要重新获取
|
||||
boolean isError = false;
|
||||
|
||||
// XSS过滤
|
||||
String regEx_xss = "script|iframe";
|
||||
//SQL过滤
|
||||
while (values.hasNext()) {
|
||||
String[] valueArray = (String[]) values.next();
|
||||
for (int i = 0; i < valueArray.length; i++) {
|
||||
// 不转换为小写,保持原始值进行检查
|
||||
String value = valueArray[i];
|
||||
// 检查是否是JSON格式
|
||||
if (isValidJson(value)) {
|
||||
// 对JSON内容进行安全检查
|
||||
if (checkJsonContent(value)) {
|
||||
// isError = true;
|
||||
log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "JSON内容包含危险字符:" + value);
|
||||
break;
|
||||
}
|
||||
// JSON格式验证通过,继续处理下一个参数
|
||||
continue;
|
||||
}
|
||||
|
||||
// 非JSON格式,进行普通的SQL注入检查
|
||||
if (containsSqlInjection(value, false)) {
|
||||
isError = true;
|
||||
log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "SQL注入风险:" + value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isError) break;
|
||||
}
|
||||
if (!isError) {
|
||||
// XSS漏洞过滤
|
||||
while (values2.hasNext()) {
|
||||
String[] valueArray = (String[]) values2.next();
|
||||
for (int i = 0; i < valueArray.length; i++) {
|
||||
String value = valueArray[i].toLowerCase();
|
||||
// 分拆关键字
|
||||
String[] inj_stra = StringUtils.split(regEx_xss, "|");
|
||||
for (int j = 0; j < inj_stra.length; j++) {
|
||||
// 判断如果路径参数值中含有关键字则返回true,并且结束循环
|
||||
if (value.contains("<" + inj_stra[j] + ">")
|
||||
|| value.contains("<" + inj_stra[j])
|
||||
|| value.contains(inj_stra[j] + ">")) {
|
||||
log.debugf("[%-4s]URI=%s %s", req.getMethod(), req.getRequestURI(), "XSS关键字过滤:" + value);
|
||||
isError = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isError) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isError) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isError;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证是否为有效的JSON
|
||||
*/
|
||||
private boolean isValidJson(String value) {
|
||||
try {
|
||||
objectMapper.readTree(value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查JSON内容是否包含危险字符
|
||||
*/
|
||||
private boolean checkJsonContent(String jsonStr) {
|
||||
try {
|
||||
JsonNode rootNode = objectMapper.readTree(jsonStr);
|
||||
return checkJsonNode(rootNode, true);
|
||||
} catch (Exception e) {
|
||||
log.error("JSON内容检查失败", e);
|
||||
return true; // 解析失败当作危险处理
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归检查JSON节点
|
||||
*/
|
||||
private boolean checkJsonNode(JsonNode node, boolean isJsonContext) {
|
||||
if (node.isObject()) {
|
||||
Iterator<Map.Entry<String, JsonNode>> fields = node.fields();
|
||||
while (fields.hasNext()) {
|
||||
Map.Entry<String, JsonNode> entry = fields.next();
|
||||
// JSON对象的键名不需要进行特殊字符检查,因为它们是受控的标识符
|
||||
// 递归检查值
|
||||
if (checkJsonNode(entry.getValue(), true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (node.isArray()) {
|
||||
for (JsonNode element : node) {
|
||||
if (checkJsonNode(element, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (node.isTextual()) {
|
||||
String value = node.asText();
|
||||
// 在JSON上下文中使用更宽松的规则
|
||||
return containsSqlInjection(value, true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否包含SQL注入风险
|
||||
*
|
||||
* @param value 要检查的值
|
||||
* @param isJsonContext 是否在JSON上下文中
|
||||
*/
|
||||
private boolean containsSqlInjection(String value, boolean isJsonContext) {
|
||||
if (StringUtils.isBlank(value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果是UUID格式,直接放行
|
||||
if (value.matches("[a-fA-F0-9]{32}") || value.matches("[a-fA-F0-9-]{36}")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果包含HTML标签,使用更宽松的检查规则
|
||||
if (value.contains("<") && value.contains(">")) {
|
||||
return checkHtmlContent(value);
|
||||
}
|
||||
|
||||
// 添加对常见标识符的检查
|
||||
if (isCommonIdentifier(value) || ALLOWED_ORDER_FIELDS.contains(value.toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查注释符号
|
||||
if (value.contains("--") || value.contains("/*") || value.contains("*/")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查危险的特殊字符(针对非JSON数据)
|
||||
if (!isValidJson(value) && containsDangerousChars(value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查SQL关键字,但要避免误判
|
||||
String valueLower = value.toLowerCase();
|
||||
for (String keyword : SQL_KEYWORDS) {
|
||||
// 在JSON上下文中,只有当关键字作为独立单词出现时才判定为危险
|
||||
if (isJsonContext) {
|
||||
if (isStandaloneWord(valueLower, keyword)) {
|
||||
return true;
|
||||
}
|
||||
} else if (valueLower.contains(keyword)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查HTML内容是否包含危险脚本
|
||||
*/
|
||||
private boolean checkHtmlContent(String html) {
|
||||
String lowerHtml = html.toLowerCase();
|
||||
// 只检查真正危险的脚本标签
|
||||
return lowerHtml.contains("<script") ||
|
||||
lowerHtml.contains("javascript:") ||
|
||||
lowerHtml.contains("onerror=") ||
|
||||
lowerHtml.contains("onclick=");
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查关键字是否作为独立单词出现
|
||||
*/
|
||||
private boolean isStandaloneWord(String text, String keyword) {
|
||||
String wordBoundary = "\\b" + keyword + "\\b";
|
||||
return Pattern.compile(wordBoundary).matcher(text).find();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否包含危险的特殊字符
|
||||
*/
|
||||
private boolean containsDangerousChars(String value) {
|
||||
// 定义真正危险的字符(减少误判)
|
||||
String[] dangerousChars = {
|
||||
// "'", // 单引号
|
||||
// ";", // 分号
|
||||
"\\", // 反斜杠
|
||||
"@@", // 系统变量前缀
|
||||
"0x", // 十六进制前缀
|
||||
"/*", // 注释开始
|
||||
"*/" // 注释结束
|
||||
};
|
||||
|
||||
for (String dangerous : dangerousChars) {
|
||||
if (value.contains(dangerous)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为常见的UUID或标识符格式
|
||||
*/
|
||||
private boolean isCommonIdentifier(String value) {
|
||||
// UUID格式
|
||||
if (value.matches("[a-fA-F0-9]{32}") || value.matches("[a-fA-F0-9-]{36}")) {
|
||||
return true;
|
||||
}
|
||||
// 常见的标识符格式(字母、数字、下划线、中划线)
|
||||
if (value.matches("^[a-zA-Z0-9_-]+$")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package com.budwk.app.web.controllers.open.commons;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.sys.models.Sys_config;
|
||||
import com.budwk.app.sys.models.Sys_dict;
|
||||
import com.budwk.app.sys.models.Sys_union;
|
||||
import com.budwk.app.sys.services.SysDictService;
|
||||
import com.budwk.app.sys.services.SysUserService;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.web.commons.base.Globals;
|
||||
import com.budwk.app.zhgh.activity.basic.models.ActivityUserScope;
|
||||
import com.budwk.app.zhgh.club.model.SysClub;
|
||||
import com.budwk.app.zhgh.club.service.SysClubService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.integration.jedis.RedisService;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 系统公共接口
|
||||
*/
|
||||
@IocBean
|
||||
@At("/open/common")
|
||||
@Ok("json:full")
|
||||
@Api(tags = "系统公共接口")
|
||||
public class CommonController {
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@Inject
|
||||
private SysDictService sysDictService;
|
||||
@Inject
|
||||
private SysUserService sysUserService;
|
||||
@Inject
|
||||
private SysClubService sysClubService;
|
||||
@Inject
|
||||
private RedisService redisService;
|
||||
|
||||
/**
|
||||
* 根据code获取字典选项,不包含禁用
|
||||
*/
|
||||
@At
|
||||
@SaCheckLogin
|
||||
@ApiOperation("获取字典选项,不包含禁用")
|
||||
public Result dictOptions(String code) {
|
||||
return Result.success(sysDictService.getSubListByCode(code));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据code获取字典选项,包含禁用
|
||||
*
|
||||
* @param code
|
||||
* @return
|
||||
*/
|
||||
@At
|
||||
@SaCheckLogin
|
||||
@ApiOperation("获取字典选项,包含禁用")
|
||||
public Result dictAllOptions(String code) {
|
||||
Sys_dict dict = sysDictService.fetch(Cnd.where("code", "=", code));
|
||||
if (dict == null) {
|
||||
return Result.success(Collections.EMPTY_LIST);
|
||||
} else {
|
||||
List<Sys_dict> query = sysDictService.query(Cnd.where("parentId", "=", Strings.sNull(dict.getId())).asc("location"));
|
||||
return Result.success(query);
|
||||
}
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckLogin
|
||||
@ApiOperation("获取枚举字典列表")
|
||||
public Result dictEnumOptions(@Valid String name) {
|
||||
if (Globals.EnumMap.containsKey(name)) {
|
||||
return Result.success().addData(Globals.EnumMap.get(name));
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckLogin
|
||||
@ApiOperation("分页查询用户,默认10条")
|
||||
public Result userOptions(String query) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.where().orLike("username", query);
|
||||
cnd.where().orLike("loginname", query);
|
||||
Pagination pagination = sysUserService.listPage(1, 10, cnd);
|
||||
return Result.success(pagination.getList());
|
||||
}
|
||||
|
||||
|
||||
@At
|
||||
@SaCheckLogin
|
||||
@ApiOperation("工会列表")
|
||||
public Result unionOptions(String unionId) {
|
||||
List<Sys_union> sys_unions = sysUserService.dao().query(Sys_union.class,
|
||||
Cnd.NEW().andEX("id", "=", unionId).asc("unionCode"));
|
||||
return Result.success(sys_unions);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckLogin
|
||||
@ApiOperation("协会列表")
|
||||
public Result clubOptions(String clubId) {
|
||||
List<SysClub> sysClubs = sysClubService.dao().query(SysClub.class,
|
||||
Cnd.NEW().andEX("id", "=", clubId));
|
||||
return Result.success(sysClubs);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckLogin
|
||||
@ApiOperation("单位列表")
|
||||
public Result unitOptions(String unionId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
unit.*,
|
||||
su.`name` AS unionName
|
||||
FROM
|
||||
`sys_unit` unit
|
||||
LEFT JOIN sys_union su ON su.id = unit.unionId
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("unit.unionId", "=", unionId);
|
||||
cnd.and("unit.unitTypeCode", "=", "1");
|
||||
cnd.asc("unit.unitcode");
|
||||
sql.setCondition(cnd);
|
||||
List<NutMap> unitList = sysUserService.listMap(sql);
|
||||
return Result.success(unitList);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckLogin
|
||||
@ApiOperation("系统配置")
|
||||
public Result getConfigKey(String key) {
|
||||
Sys_config configKey = sysDictService.dao().fetch(Sys_config.class, Cnd.where("configKey", "=", key));
|
||||
return Result.success().addData(configKey.getConfigValue());
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckLogin
|
||||
@ApiOperation("检查用户组权限")
|
||||
public Result checkGroupPermission(String groupId) {
|
||||
int count = dao.count(ActivityUserScope.class, Cnd.where(ActivityUserScope::getGroupId, "=", groupId).and(ActivityUserScope::getUserId, "=", SecurityUtil.getUserId()));
|
||||
return Result.success(count > 0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.budwk.app.web.controllers.open.commons.service;
|
||||
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
import com.budwk.app.sys.models.Sys_user_role;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.util.lambda.PFun;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @Author: JyuHsin
|
||||
* @Date: 2024/8/9 15:41
|
||||
* @Version: v1.0.0
|
||||
* @Description: TODO
|
||||
**/
|
||||
public interface CommonService extends BaseService {
|
||||
|
||||
/**
|
||||
* 根据角色code获取用户信息
|
||||
*
|
||||
* @param column sys_user_role表中的列,比如要查分工会管理员,那么column=unionId
|
||||
* @param columnValue sys_user_role表中列的值,比如要查分工会管理员,columnValue=分工会的id
|
||||
* @param roleCode 角色code,主要需要.name()后传过来
|
||||
* @return 用户实体类集合
|
||||
*/
|
||||
List<Sys_user> findUserInfoByRoleCode(String column, String columnValue, @Valid String roleCode);
|
||||
|
||||
/**
|
||||
* 根据多个角色code获取用户信息
|
||||
*
|
||||
* @param column 见上
|
||||
* @param columnValue 见上
|
||||
* @param roleCode 见上
|
||||
* @return 见上
|
||||
*/
|
||||
List<Sys_user> findUserInfoByRoleCode(String column, String columnValue, @Valid List<String> roleCode);
|
||||
|
||||
/**
|
||||
* 根据角色code获取用户信息,这个主要是来获取校级层面的
|
||||
*
|
||||
* @param roleCode 见上
|
||||
* @return 见上
|
||||
*/
|
||||
List<Sys_user> findUserInfoByRoleCode(@Valid String roleCode);
|
||||
|
||||
/**
|
||||
* 根据角色code获取角色id
|
||||
*
|
||||
* @param roleCode 角色code,主要需要.name()后传过来
|
||||
* @return roleId的集合
|
||||
*/
|
||||
List<String> findUserRoleByRoleCode(@Valid String roleCode);
|
||||
|
||||
/**
|
||||
* 根据多个角色code获取角色id
|
||||
*
|
||||
* @param roleCode 见上
|
||||
* @return roleId的集合
|
||||
*/
|
||||
List<String> findUserRoleByRoleCode(@Valid List<String> roleCode);
|
||||
|
||||
<T> List<Sys_user> findUserInfoByRoleCode(PFun<T, ?> name, String columnValue, RoleConstant... roleConstants);
|
||||
|
||||
|
||||
/**
|
||||
* 下述为修正版
|
||||
*/
|
||||
|
||||
/**
|
||||
* 根据角色code获取多个用户工号
|
||||
*
|
||||
* @param roleConstant
|
||||
* @return
|
||||
*/
|
||||
List<String> findUsersLoginNameByRoleCode(RoleConstant roleConstant);
|
||||
|
||||
/**
|
||||
* 根据角色code获取多个用户工号
|
||||
*
|
||||
* @param roleConstant
|
||||
* @return
|
||||
*/
|
||||
List<String> findUsersLoginNameByRoleCode(RoleConstant roleConstant, Cnd cnd);
|
||||
|
||||
|
||||
/**
|
||||
* 根据角色code获取一个用户工号
|
||||
*
|
||||
* @param roleConstant
|
||||
* @return
|
||||
*/
|
||||
String findUserLoginNameByRoleCode(RoleConstant roleConstant);
|
||||
|
||||
/**
|
||||
* 根据角色code获取一个用户工号
|
||||
*
|
||||
* @param roleConstant
|
||||
* @return
|
||||
*/
|
||||
String findUserLoginNameByRoleCode(RoleConstant roleConstant, Cnd cnd);
|
||||
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
package com.budwk.app.web.controllers.open.commons.service.impl;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.sys.models.Sys_role;
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
import com.budwk.app.sys.models.Sys_user_role;
|
||||
import com.budwk.app.sys.services.SysRoleService;
|
||||
import com.budwk.app.web.controllers.open.commons.service.CommonService;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.lambda.LambdaQuery;
|
||||
import org.nutz.dao.util.lambda.PFun;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @Author: JyuHsin
|
||||
* @Date: 2024/8/9 15:41
|
||||
* @Version: v1.0.0
|
||||
* @Description: TODO
|
||||
**/
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class CommonServiceImpl extends BaseServiceImpl implements CommonService {
|
||||
|
||||
@Inject
|
||||
private SysRoleService sysRoleService;
|
||||
|
||||
public CommonServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Sys_user> findUserInfoByRoleCode(String roleCode) {
|
||||
return findUserInfoByRoleCode(null, null, List.of(roleCode));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Sys_user> findUserInfoByRoleCode(String column, String columnValue, String roleCode) {
|
||||
return findUserInfoByRoleCode(column, columnValue, List.of(roleCode));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Sys_user> findUserInfoByRoleCode(String column, String columnValue, List<String> roleCode) {
|
||||
Assert.notEmpty(roleCode);
|
||||
|
||||
List<String> roleIdList = new ArrayList<>();
|
||||
|
||||
roleCode.forEach(role -> {
|
||||
Sys_role sysRole = sysRoleService.getByCode(role);
|
||||
roleIdList.add(sysRole.getId());
|
||||
});
|
||||
|
||||
Cnd cnd = Cnd.where("roleId", "in", roleIdList);
|
||||
if (StrUtil.isNotBlank(column)) {
|
||||
cnd.andEX(column, "=", columnValue);
|
||||
}
|
||||
|
||||
List<Sys_user_role> roleList = dao().query(Sys_user_role.class, cnd);
|
||||
List<String> userIdList = roleList.stream().map(Sys_user_role::getUserId).distinct().toList();
|
||||
|
||||
return dao().query(Sys_user.class, Cnd.where("id", "in", userIdList));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> findUserRoleByRoleCode(String roleCode) {
|
||||
return findUserRoleByRoleCode(List.of(roleCode));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> findUserRoleByRoleCode(List<String> roleCode) {
|
||||
List<Sys_role> roleList = new ArrayList<>();
|
||||
roleCode.forEach(role -> {
|
||||
roleList.add(sysRoleService.getByCode(role));
|
||||
});
|
||||
return roleList.stream().map(Sys_role::getId).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<Sys_user> findUserInfoByRoleCode(PFun<T, ?> name, String columnValue, RoleConstant... roleConstant) {
|
||||
String column = LambdaQuery.resolve(name);
|
||||
|
||||
List<String> list = Arrays.stream(roleConstant).map(Enum::name).toList();
|
||||
return findUserInfoByRoleCode(column, columnValue, list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> findUsersLoginNameByRoleCode(RoleConstant roleConstant) {
|
||||
return findUsersLoginNameByRoleCode(roleConstant,Cnd.NEW());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> findUsersLoginNameByRoleCode(RoleConstant roleConstant, Cnd cnd) {
|
||||
Sys_role sysRole = sysRoleService.getByCode(roleConstant);
|
||||
cnd.and(Sys_user_role::getRoleId, "=", sysRole.getId());
|
||||
List<Sys_user_role> sysUserRoles = dao().query(Sys_user_role.class, cnd);
|
||||
List<String> userIds = sysUserRoles.stream().map(Sys_user_role::getUserId).toList();
|
||||
if(ObjectUtil.isEmpty(userIds)){
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Sql sql = Sqls.create("select loginname from sys_user where id in (@userIds)").setParam("userIds", userIds);
|
||||
sql.setCallback(Sqls.callback.strList());
|
||||
dao().execute(sql);
|
||||
return sql.getList(String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findUserLoginNameByRoleCode(RoleConstant roleConstant) {
|
||||
return findUserLoginNameByRoleCode(roleConstant, Cnd.NEW());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findUserLoginNameByRoleCode(RoleConstant roleConstant, Cnd cnd) {
|
||||
Sys_role sysRole = sysRoleService.getByCode(roleConstant);
|
||||
cnd.and(Sys_user_role::getRoleId, "=", sysRole.getId());
|
||||
Sys_user_role sysUserRole = dao().fetch(Sys_user_role.class, cnd);
|
||||
if (ObjectUtil.isNotEmpty(sysUserRole)) {
|
||||
return dao().fetch(Sys_user.class, sysUserRole.getUserId()).getLoginname();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user