作者 朱兆平

brench-update:

1. 转关运抵列表接口增加数据权限过滤-增加列过滤.

Signed-off-by: mrz <17966059@qq.com>
package com.tianbo.analysis.intercept;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.tianbo.analysis.thread.SessionUserContext;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.Join;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectItem;
import net.sf.jsqlparser.statement.select.*;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
... ... @@ -25,9 +25,11 @@ import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Intercepts({
@Signature(type= Executor.class,
method = "query",
... ... @@ -80,16 +82,33 @@ public class DataPermissionInterceptor implements Interceptor {
* todo: 条件值怎么获取?
*/
String dataScope = "els";
JSONArray rowPermList = SessionUserContext.getSessionUser();
//取出来后 清理
SessionUserContext.clearSessionUser();
if (rowPermList!=null && !rowPermList.isEmpty()) {
// 用户配置了数据权限
//获取该用户所具有的角色的数据权限dataScope
dataScope = "usr";
}else {
//用户未配置数据权限
dataScope = "*";
JSONObject user = SessionUserContext.getSessionUser();
String username = user.getString("username");
Integer userId = user.getInteger("userId");
JSONArray dataPermissions = user.getJSONArray("dataPermissions");
//存储行条件数据权限
ArrayList<JSONObject> rowConditions = new ArrayList<>();
JSONArray colConditions = new JSONArray();
if (dataPermissions!=null && !dataPermissions.isEmpty()){
for (Object item : dataPermissions) {
JSONObject datapermission = (JSONObject) JSON.toJSON(item);
/**
* 一个组织绑定了同一个接口的多个数据权限,循环到这里 会出现 * 条件和 usr条件混乱,
* 目前 以循环 最后取到的row_condition为准,所以需要保持 数据权限配置数据正确
*/
dataScope = datapermission.getString("perm_type");
String colListStr = datapermission.getString("cols_list");
if (StringUtils.isNotEmpty(colListStr)){
if ("*".equals(colListStr)) {
//查询全部列,不改
}else{
JSONArray cloArrayList = JSONArray.parseArray(colListStr);
colConditions.addAll(cloArrayList);
}
}
rowConditions.add(datapermission);
}
}
String deptsUser= "admin";
... ... @@ -108,6 +127,7 @@ public class DataPermissionInterceptor implements Interceptor {
PlainSelect plain = (PlainSelect) selectStatement.getSelectBody();
//获取所有外连接
List<Join> joins = plain.getJoins();
//获取到原始sql语句
String sql = processSql;
StringBuffer whereSql = new StringBuffer();
... ... @@ -123,22 +143,22 @@ public class DataPermissionInterceptor implements Interceptor {
case "usr":
if(joins==null || joins.isEmpty()){
String and = " and ";
for (int i = 0; i < rowPermList.size(); i++) {
JSONObject o = (JSONObject)rowPermList.get(i);
for (int i = 0; i < rowConditions.size(); i++) {
JSONObject dataPermission = rowConditions.get(i);
if (i==0){
whereSql
//条件字段
.append(o.get("colName"))
.append(dataPermission.get("row_condition"))
.append(" = ")
// 条件值
.append(getSqlValue(o.get("colValue")));
.append(getSqlValue(user.get(dataPermission.getString("row_condition_property"))));
}else {
whereSql.append(and)
//条件字段
.append(o.get("colName"))
.append(dataPermission.get("row_condition"))
.append(" = ")
// 条件值
.append(getSqlValue(o.get("colValue")));
.append(getSqlValue(user.get(dataPermission.getString("row_condition_property"))));
}
}
... ... @@ -189,6 +209,13 @@ public class DataPermissionInterceptor implements Interceptor {
whereSql.append("1=2");
break;
}
/**
* 替换select 节点
*/
if (!colConditions.isEmpty()){
List<SelectItem> selectExpressionItems = resetColumn(colConditions);
plain.setSelectItems(selectExpressionItems);
}
/**
* 获取where节点
... ... @@ -240,4 +267,18 @@ public class DataPermissionInterceptor implements Interceptor {
return value.toString();
}
}
/**
* 重新设置select的字段
* @param newSelectItems 要重设置的字段列表
* @return 重新设置后的字段列表
*/
private List<SelectItem> resetColumn(JSONArray newSelectItems){
List<SelectItem> newSelectExpressionItems = new ArrayList<>();
for (Object newSelectItem : newSelectItems) {
SelectItem selectExpressionItem = new SelectExpressionItem(new Column(newSelectItem.toString()));
newSelectExpressionItems.add(selectExpressionItem);
}
return newSelectExpressionItems;
}
}
... ...
package com.tianbo.analysis.intercept;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.tianbo.analysis.exception.TransArriveException;
import com.tianbo.analysis.feign.UserCenterAPI;
import com.tianbo.analysis.model.ResultJson;
import com.tianbo.analysis.thread.SessionUserContext;
... ... @@ -10,7 +10,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.PostConstruct;
... ... @@ -38,65 +37,39 @@ public class UserCenterHanlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.debug("进入HTTPServletRequest 拦截器");
String serviceName = _THIS.environment.getProperty("spring.application.name");
String permPath = "/" + serviceName + request.getRequestURI();
log.info("path = {}, serviceName= {}",request.getRequestURI(),serviceName);
AntPathMatcher pathMatcher = new AntPathMatcher();
boolean match = pathMatcher.match(permPath, request.getRequestURI());
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
/**
* 根据访问接口地址和token信息获取用户权限信息
* 参数为request 中的接口地址和的 auth 的token信息
* 样例实体类如下:
* todo:后期返回数据 要增加用户所属的同级组织机构的用户列表dep,或者 同公司下的用户列表com
*/
ResultJson resultJson = _THIS.userCenterAPI.getDataPerm(permPath, authHeader);
if (resultJson.getData()!=null){
/**
* 下面JSONObject user为 cloud-user-center中的users类.
* 为了方便,使用jsonObject进行使用.
*/
JSONObject user = (JSONObject) JSON.toJSON(resultJson.getData());
SessionUserContext.setSessionUser(user);
}else{
throw new TransArriveException("无用户数据权限获取失败,无法访问");
}
JSONObject user = (JSONObject) JSON.toJSON(resultJson.getData());
log.info(resultJson.toString());
}
/**
* 根据访问接口地址和token信息获取用户权限信息
* 参数为request 中的接口地址和的 auth 的token信息
* 样例实体类如下:
*/
String userDataPermJsonDemoStr = "{\n" +
"\t\"username\":\"nmms\",\n" +
"\t\"userId\": \"80\",\n" +
"\t\"userDataPerm\":{\n" +
"\t\t\"rowCondition\": \"usr\",\n" +
"\t\t\"rowDataPermConditions\":[\n" +
"\t\t\t{\n" +
"\t\t\t\t\"colName\": \"USERNAME\"\n" +
"\t\t\t},\n" +
"\t\t\t{\n" +
"\t\t\t\t\"colName\": \"BILLNO\"\n" +
"\t\t\t}\n" +
"\t\t],\n" +
"\t}\t\n" +
"}";
JSONObject userInfo = JSONObject.parseObject(userDataPermJsonDemoStr);
JSONObject userDataPerm = userInfo.getJSONObject("userDataPerm");
String rowCondition = userDataPerm.getString("rowCondition");
JSONArray rowDataPermConditions = userDataPerm.getJSONArray("rowDataPermConditions");
JSONObject userDataPermModel = new JSONObject();
userDataPermModel.put("colName","USERNAME");
//获取token中的user的值
userDataPermModel.put("colValue","nmms");
// JSONObject userDataPermModel1 = new JSONObject();
// userDataPermModel1.put("colName","BILLNO");
// userDataPermModel1.put("colValue","78464771722");
JSONArray userDataPermArray = new JSONArray();
userDataPermArray.add(userDataPermModel);
// userDataPermArray.add(userDataPermModel1);
SessionUserContext.setSessionUser(userDataPermArray);
log.info("进入HTTPServletRequest 拦截器");
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
SessionUserContext.clearSessionUser();
}
}
... ...
package com.tianbo.analysis.thread;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
public class SessionUserContext {
private static final ThreadLocal<JSONArray> SESSION_USER_THREAD_LOCAL = new ThreadLocal();
private static final ThreadLocal<JSONObject> SESSION_USER_THREAD_LOCAL = new ThreadLocal();
public static void setSessionUser(JSONArray sessionUser){
public static void setSessionUser(JSONObject sessionUser){
SESSION_USER_THREAD_LOCAL.set(sessionUser);
}
... ... @@ -15,8 +14,8 @@ public class SessionUserContext {
SESSION_USER_THREAD_LOCAL.remove();
}
public static JSONArray getSessionUser(){
return (JSONArray) SESSION_USER_THREAD_LOCAL.get();
public static JSONObject getSessionUser(){
return (JSONObject) SESSION_USER_THREAD_LOCAL.get();
}
/** 下面可以添加获取用户ID或者用户名的方法例子:
... ...
... ... @@ -96,25 +96,26 @@
) t2 ON t1.AUTOID = t2.CLIENTSEQNO
AND t2.rn = 1
) t3
where 1=1
<if test="customscode != null and customscode != ''" >
and CustomsCode = #{customscode,jdbcType=VARCHAR}
</if>
<if test="username != null and username != ''">
and USERNAME = #{username,jdbcType=VARCHAR}
</if>
<if test="trnmode != null and trnmode != ''" >
and TrnMode = #{trnmode,jdbcType=VARCHAR}
</if>
<if test="unloadcode != null and unloadcode != ''" >
and UnloadCode = #{unloadcode,jdbcType=VARCHAR}
</if>
<if test="billno != null and billno != ''" >
and BillNo = #{billno,jdbcType=VARCHAR}
</if>
<if test="creattimeStart != null and creattimeEnd != null" >
and CREATTIME between #{creattimeStart,jdbcType=TIMESTAMP} and #{creattimeEnd,jdbcType=TIMESTAMP}
</if>
<where>
<if test="customscode != null and customscode != ''" >
and CustomsCode = #{customscode,jdbcType=VARCHAR}
</if>
<if test="username != null and username != ''">
and USERNAME = #{username,jdbcType=VARCHAR}
</if>
<if test="trnmode != null and trnmode != ''" >
and TrnMode = #{trnmode,jdbcType=VARCHAR}
</if>
<if test="unloadcode != null and unloadcode != ''" >
and UnloadCode = #{unloadcode,jdbcType=VARCHAR}
</if>
<if test="billno != null and billno != ''" >
and BillNo = #{billno,jdbcType=VARCHAR}
</if>
<if test="creattimeStart != null and creattimeEnd != null" >
and CREATTIME between #{creattimeStart,jdbcType=TIMESTAMP} and #{creattimeEnd,jdbcType=TIMESTAMP}
</if>
</where>
order by CREATTIME desc
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String" >
... ...