
cn.benma666.sjsj.web.UserManager Maven / Gradle / Ivy
/**
* Project Name:myutils
* Date:2018年12月19日
* Copyright (c) 2018, jingma All Rights Reserved.
*/
package cn.benma666.sjsj.web;
import cn.benma666.constants.SysAuth;
import cn.benma666.constants.UtilConst;
import cn.benma666.constants.UtilConstInstance;
import cn.benma666.crypt.DesUtil;
import cn.benma666.dict.Zdlb;
import cn.benma666.domain.SysQxJgxx;
import cn.benma666.domain.SysQxYhxx;
import cn.benma666.domain.SysSjglSjdx;
import cn.benma666.exception.MyException;
import cn.benma666.exception.NotFindUserException;
import cn.benma666.iframe.*;
import cn.benma666.myutils.DateUtil;
import cn.benma666.myutils.StringUtil;
import cn.benma666.sjzt.Db;
import cn.benma666.sjzt.SjsjField;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.beetl.sql.core.SqlId;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import java.net.URLEncoder;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 用户管理器
* date: 2018年12月19日
* @author jingma
*/
public class UserManager extends BasicObject {
/**
* 临时用户
*/
public static final String LSYH = UtilConst.LSYH;
/**
* 登陆凭证
*/
public static final String TOKEN = "token";
/**
* 登陆时间KEY
*/
public static final String DLSJ = "dlsj";
/**
* 全部权限信息缓存
*/
protected static final JSONObject authAllCache = CacheFactory.use("authAll", CacheFactory.TYPE_MEMORY);
/**
* 会话缓存
*/
private static final JSONObject hhCache = CacheFactory.use("hhCache");
/**
* redis工具
*/
private static RedisTemplate redisTemplate;
/**
* 会话有效期(分钟)
*/
private static long sessionYxq = 12*60;
/**
* 用户信息缓存
*/
private static final JSONObject userCache = CacheFactory.use(LjqInterface.KEY_USER);
public UserManager(RedisTemplate redisTemplate) {
UserManager.redisTemplate = redisTemplate;
sessionYxq = DateUtil.scSjStrToLong(Conf.getVal("server.servlet.session.timeout",
sessionYxq+"m"))/60000;
}
/**
* @return 根据token获取用户
*/
public static SysQxYhxx getUser(String token) {
MyParams myParams = new MyParams();
myParams.set(UtilConst.$_SYS_TOKEN,token);
return getUser(myParams);
}
/**
* 获取用户信息
*
* @param myParams 参数
* @return 用户信息,当token为空时返回空
* @author jingma
*/
public static SysQxYhxx getUser(MyParams myParams) {
String token = myParams.getString(LjqInterface.$_SYS_TOKEN);
//已经获取过用户了
SysQxYhxx user = myParams.getObject(LjqInterface.KEY_USER,SysQxYhxx.class);
if(user==null){
if (StringUtil.isBlank(token)) {
//token一般来说一定会有值,没有值为系统内部调用
return null;
}
synchronized (userCache){
user = userCache.getObject(token,SysQxYhxx.class);
}
}else {
//直接返回
return user;
}
if(user!=null){
long dlsj = (long) user.get(DLSJ);
if(System.currentTimeMillis()-dlsj>sessionYxq*60000){
//过期
synchronized (userCache){
userCache.remove(token);
zxhhjy(user);
}
user = null;
}else{
//重置有效期
if(redisTemplate!=null){
redisTemplate.expire(LjqInterface.KEY_USER+":"+token,sessionYxq, TimeUnit.MINUTES);
}
user.set(DLSJ,System.currentTimeMillis());
}
}
if(user==null&&redisTemplate!=null){
Object obj = redisTemplate.opsForValue().get(LjqInterface.KEY_USER+":"+token);
if(obj != null) {
//本系统过期,或本系统第一次访问,其他子系统还在访问的场景
user = (SysQxYhxx) obj;
addUser(token,user);
}
}
//实现免登陆,处理带用户信息的url
if (user == null || (LSYH.equals(user.getYhdm()) && myParams.getString("$.sys.userInfo") != null)) {
//第一次请求或(是临时用户且提供了加密用户信息)
return zddl(myParams, token);
}
return user;
}
/**
* 将用户信息加密,然后重定向到指定url
* @param url 待转发地址
* @param projectCode 项目代码
* @param user 用户标志,默认为用户身份证号,可以采用“yhdm=xxx”的形式传入用户代码进行自动登陆
* @return 带用户信息的地址
* @author jingma
*/
public static String doDesEncryptUrl(String url, String projectCode, String user){
String token = defaultCache.getString(projectCode + user);
if(isBlank(token)){
//避免每次都进行完整的登录
token=StringUtil.getUUIDUpperStr();
defaultCache.put(projectCode + user,token);
}
String userInfo = enUserinfo(projectCode, user);
JSONObject app = DictManager.zdObjByDm(Zdlb.SYS_QX_APP.name(), projectCode);
try {
url = app.getString("dz") + url;
int idx = url.indexOf("?");
if (idx > -1) {
//解决url中包含中文参数导致转发后中文信息丢失问题。
StringBuilder url1 = new StringBuilder(url.substring(0, idx + 1));
for (String p : url.substring(idx + 1).split("&")) {
String[] pa = p.split("=");
url1.append(pa[0]).append("=").append(URLEncoder.encode(pa[1], "utf8")).append("&");
}
url = url1.toString();
} else {
url += "?";
}
url += "sys.userInfo=" + URLEncoder.encode(userInfo, "utf8")+"&sys.token="+token;
if(!url.startsWith("http")){
//配置的相对地址则读取配置的统一代理地址进行补充
url = Conf.getUtilConfig().getService().getTydlzd()+url;
}
return url;
} catch (Exception e) {
throw new MyException(projectCode+"生成用户信息转发地址失败:" + e.getMessage());
}
}
/**
* 加密用户信息
* @param projectCode 应用代码
* @param user 用户代码
* @return 加密串
*/
public static String enUserinfo(String projectCode, String user) {
String userInfo;
userInfo = DateUtil.getGabDate() + "@" + user;
JSONObject app = DictManager.zdObjByDm(Zdlb.SYS_QX_APP.name(), projectCode);
if(app ==null){
throw new MyException("该请求的应用不存在:"+ projectCode);
}
String pwd = app.getString("mm");
if (StringUtil.isBlank(pwd)) {
throw new MyException("应用必须设置密码:"+ projectCode);
}
pwd = DesUtil.decrypt(pwd, Conf.getUtilConfig().getAppEjmm());
userInfo = DesUtil.encrypt(userInfo, pwd).replaceAll("[\n\r]", "");
return userInfo;
}
/**
* 自动登陆
* @param myParams 参数
* @param token 权限认证key
* @return 登陆后的用户信息
* @author jingma
*/
public static SysQxYhxx zddl(MyParams myParams, String token) {
SysQxYhxx user = null;
Object obj = myParams.get("$.sys.userInfo");
if (!StringUtil.isBlank(obj)) {
String userInfo = obj.toString();
if(userInfo.startsWith("sqm-")){
//授权码机制
String sqm = userInfo.substring(4);
if(isBlank(sqm)){
throw new MyException("自动登录授权码为空");
}
MyParams p = new MyParams();
p.set("$.yobj.sqm", sqm);
user = findUser(p,true);
}else {
JSONObject app = DictManager.zdObjByDm(Zdlb.SYS_QX_APP.name(),
Conf.getAppdm());
String pwd = app.getString("mm");
String zddlms = app.getString("zddlms");
if (StringUtil.isBlank(pwd)) {
throw new MyException("应用未设置密码", myParams);
}
try {
//解密应用密码
pwd = DesUtil.decrypt(pwd, Conf.getUtilConfig().getAppEjmm());
} catch (Exception e) {
throw new MyException("解析用户信息失败:" + userInfo + ">" + e.getMessage(), e);
}
if ("date_user".equals(zddlms)) {
//用户时间加密模式,用户信息解密
userInfo = DesUtil.decrypt(userInfo, pwd);
}
int idx = userInfo.indexOf("@");
if ("date_user".equals(zddlms)) {
//用户时间加密模式,推荐使用
Date urlDate = DateUtil.parseDate(userInfo.substring(0, idx));
assert urlDate != null;
if (Math.abs(urlDate.getTime() - new Date().getTime()) > 1000 * 60 * 5) {
throw new MyException("用户信息过期:" + userInfo, myParams);
}
} else if ("pwd_user".equals(zddlms)) {
String ipxz = JSON.parseObject(app.getString("kzxx")).getString("ipxz");
if(StringUtil.isBlank(ipxz)){
throw new MyException("一般密码模式自动登陆的应用必须配置ip限制:" + userInfo, myParams);
}
if(!myParams.getString("$.sys.clientIp").matches(ipxz)){
throw new MyException("请在规定的ip机器上访问:" + userInfo, myParams);
}
if(!pwd.equals(userInfo.substring(0, idx))){
//明文密码加用户模式,内部调用
throw new MyException("密码不正确:" + userInfo, myParams);
}
}
user = findUser(userInfo.substring(idx + 1));
}
slog.info("自动登陆成功:" + user.getSfzh());
}
//没有登录时,返回临时用户,后续可以在权限系统中对临时用户进行授权
if (user == null) {
synchronized (userCache){
obj = userCache.getString(LSYH);
}
if(obj==null){
user = findUser(LSYH);
addUser(LSYH, user);
user = JSON.parseObject(user.toString(),SysQxYhxx.class);
}else{
//避免对象复用
user = JSON.parseObject(obj.toString(),SysQxYhxx.class);
}
}
if (StringUtil.isNotBlank(user.getXzip())
&& !user.getClientIp().matches(user.getXzip())) {
throw new MyException("你未不在授权的ip范围内登录:" + user, myParams);
} else {
addUser(token, user);
}
return user;
}
/**
* 添加用户
* @param token 权限码
* @param user 用户信息
* @author jingma
*/
public static void addUser(String token, SysQxYhxx user) {
qcgqyhhc();
if (StringUtil.isNotBlank(token)) {
synchronized (userCache){
SysQxYhxx oldUser = userCache.getObject(token, SysQxYhxx.class);
if(oldUser==null||!oldUser.getId().equals(user.getId())){
//若当前登录用户不是已经登录的用户
synchronized (hhCache) {
int yhhhs = hhCache.getIntValue("yhhhs_" + user.getId());
if (!LSYH.equals(user.getYhdm()) && yhhhs > valByDef(Conf.getUtilConfig().getLogin().getTszxhhsxz(), 20)) {
throw new MyException("你同时在线会话数超过系统限制");
}
//对该用户在线会话计数
hhCache.put("yhhhs_" + user.getId(), yhhhs + 1);
}
}
user.setToken(token);
//设置登陆时间
user.set(DLSJ,System.currentTimeMillis());
userCache.put(token,user);
if(redisTemplate!=null){
redisTemplate.opsForValue().set(LjqInterface.KEY_USER+":"+token, user, sessionYxq, TimeUnit.MINUTES);
}
}
} else {
slog.debug("权限码为空:" + user);
}
}
/**
* 移除登陆的用户,用户登陆退出
*
* @param user 要移除的用户
* @return 处理结果
* @author jingma
*/
public static Result removeUser(SysQxYhxx user) {
if(redisTemplate!=null){
redisTemplate.delete(LjqInterface.KEY_USER+":"+user.getToken());
}
synchronized (userCache){
userCache.remove(user.getToken());
zxhhjy(user);
}
return success("退出成功");
}
public static SysQxYhxx findUser(String userStr) {
return findUser(userStr,true);
}
/**
* 获取用户信息
* @param userStr 用户信息字符串,支持id、身份证、代码、微信id
* @return 用户完整信息
*/
@NotNull
public static SysQxYhxx findUser(String userStr,boolean cache) {
if (userStr.startsWith("yhdm=")) {
userStr = userStr.substring(5);
} else if (userStr.startsWith("id=")) {
userStr = userStr.substring(3);
}
MyParams myParams = new MyParams();
myParams.set("$.yobj.yhdm", userStr);
return findUser(myParams,cache);
}
/**
* 获取用户的完整信息,包括基础信息、机构、权限
*
* @param myParams 参数集合
* @return 用户信息
* @author jingma
*/
public static SysQxYhxx findUser(MyParams myParams,boolean cache) throws MyException {
SysQxYhxx yobj = myParams.yobj(SysQxYhxx.class);
//设置终端类别,不同终端权限不一样,有些功能手机端不支持
yobj.setZdlb(myParams.sys().getZdlb());
Object o = defaultCache.get(yobj.toString());
if(o!=null&&cache){
return (SysQxYhxx) o;
}
//查询用户
SysQxYhxx user;
user = Db.useSqlManager().selectSingle(SqlId.of("sjsj", "findUser"), myParams, SysQxYhxx.class);
if(user==null){
throw new NotFindUserException("没有找到用户:"+yobj);
}
user.setZdlb(myParams.sys().getZdlb());
//查询机构
SysQxJgxx jgxx = Db.use().lambdaQuery(SysQxJgxx.class).andEq(SysQxJgxx::getId,user.getSsjg()).singleSimple();
if(jgxx==null){
throw new MyException("没有找到用户的机构:"+user);
}
user.setJgxx(jgxx);
loadYhqx(user);
if(cache){
defaultCache.put(yobj.toString(),user);
}
return user;
}
/**
* 刷新用户权限信息
*
* @author jingma
* @param myParams 参数对象
*/
public static void flushUserQxxx(MyParams myParams) {
SysQxYhxx user;
synchronized (userCache){
if(redisTemplate!=null){
//使用redis
final Cursor scan = redisTemplate.scan(ScanOptions.scanOptions().match("user*").build());
while (scan.hasNext()){
final String key = scan.next();
user = ((SysQxYhxx) redisTemplate.opsForValue().get(key));
assert user != null;
loadYhqx(user);
userCache.put(user.getToken(),user);
redisTemplate.opsForValue().set(key,user,sessionYxq, TimeUnit.MINUTES);
}
}else{
//不使用redis
for (String key : userCache.keySet()) {
user = userCache.getObject(key,SysQxYhxx.class);
loadYhqx(user);
userCache.put(key,user);
}
}
}
}
/**
* 清除过期用户缓存
*/
private static void qcgqyhhc(){
SysQxYhxx user;
long dlsj;
synchronized (userCache){
Iterator> uc = userCache.entrySet().iterator();
while (uc.hasNext()) {
Map.Entry e = uc.next();
user = (SysQxYhxx) e.getValue();
dlsj = (long) user.get(DLSJ);
if(System.currentTimeMillis()-dlsj>sessionYxq*60000){
zxhhjy(user);
//过期
uc.remove();
}
}
}
}
/**
* 用户在线会话减一
* @param user 用户信息
*/
private static void zxhhjy(SysQxYhxx user){
//该用户会话数减一
synchronized (hhCache){
hhCache.put("yhhhs_"+user.getId(),hhCache.getIntValue("yhhhs_"+user.getId())-1);
}
}
/**
* 加载用户权限相关信息:角色、权限、对象代码与权限的映射
*/
private static void loadYhqx(SysQxYhxx user){
JSONObject params = Db.buildKeyMap(UtilConstInstance.KEY_USER, user);
//查询角色
user.setJsMap(Db.use().findMap("js",SqlId.of("sjsj","findJsxx"),params));
//设置用户权限
user.setQxMap(Db.use().findMap("dm", SqlId.of("sjsj","findYhqxxx"), params));
//设置用户相关对象与权限代码的映射关系
user.setDxqxys(Db.use().findMap("dxdm", SqlId.of("sjsj","findYhDxQxYs"), params));
//设置登陆时间,计算会话超时
user.set(DLSJ,System.currentTimeMillis());
}
public static boolean hasAuth(MyParams myParams){
return hasAuth(myParams,myParams.sys().getCllx());
}
public static boolean hasAuth(MyParams myParams,String cllx){
return hasAuth(myParams.user(),myParams.sys().getAuthCode(),cllx,
myParams.sjdx(),myParams.sys().getNbdy());
}
public static boolean hasAuth(SysQxYhxx user,String authCode,String cllx){
return hasAuth(user,authCode+"_"+cllx);
}
public static boolean hasAuth(SysQxYhxx user,String qxm){
return hasAuth(user,qxm,null,false);
}
public static boolean hasAuthByUser(JSONObject user,String qxm){
return hasAuth(user.toJavaObject(SysQxYhxx.class),qxm,null,false);
}
public static boolean hasAuth(SysQxYhxx user,String authCode,String cllx,SysSjglSjdx sjdx,boolean nbdy) {
if (authCode == null) {
//没有配置权限时则统一采用未授权对象的权限
authCode = SysAuth.QTQX_WSQDX.name();
}
//最终权限码
String qxm = authCode + "_" + cllx;
return hasAuth(user, qxm, sjdx, nbdy);
}
public static boolean hasAuth(SysQxYhxx user,String qxm,SysSjglSjdx sjdx,boolean nbdy){
//有权限
boolean yqx = false;
if (nbdy||user==null||user.getQxMap().containsKey(SysAuth.QTQX_SYS.name())) {
//内部调用或内部调用没有用户或拥有最高权限,则默认通过。
yqx = true;
}else{
synchronized (authAllCache){
if(authAllCache.isEmpty()){
//权限缓存为空则读取权限信息并缓存
authAllCache.putAll(Db.use().findMap("dm", SqlId.of("sjsj",
"findYhqxxx"), Db.buildMap()));
}
}
//没有配置权限的接口登陆用户可以直接访问,配置了权限的接口必须授权才能访问
if(!authAllCache.containsKey(qxm)&&!UtilConst.LSYH.equals(user.getYhdm())){
yqx = true;
}else if (user.getQxMap().containsKey(qxm)) {
//对象权限判断
yqx = true;
}
String sqms = valByDef(Conf.getUtilConfig().getXtqxSqms(), SjsjField.cllx.name());
switch (sqms){
case "sjdx":
if(!yqx&&sjdx!=null){
//数据对象不为空,为空则走处理类型校验
yqx = user.getDxqxys().containsKey(sjdx.getDxdm());
}
break;
case "cllx":
break;
default:
throw new MyException("暂不支持该授权模式:"+sqms);
}
}
return yqx;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy