APIJSON(十二:AbstractVerifier源码阅读(3))

APIJSON(十二:AbstractVerifier源码阅读(3))

2021SC@SDUSC

verifyAccess

此方法为验证权限是否通过

public boolean verifyAccess(SQLConfig config) throws Exception

其传入的参数为SQLConfig中的一个对象,而SQLConfig中存储的为数据库的配置。

首先会判断是否为空,如果为空,会直接通过(虽然这里不是很明白?可能是一开始配置未初始化,为了方便测试?)

String table = config == null ? null : config.getTable();
if (table == null) {
   return true;
}

之后会获取角色。如果获取的为空值,就会自动将角色设置为UNKNOWN

String role = config.getRole();
if (role == null) {
   role = UNKNOWN;
} 
else { 
   if (ROLE_MAP.containsKey(role) == false) {
      Set<String> NAMES = ROLE_MAP.keySet();
      throw new IllegalArgumentException("角色 " + role + " 不存在!只能是[" + StringUtil.getString(NAMES.toArray()) + "]中的一种!");
   }

   if (role.equals(UNKNOWN) == false) { //未登录的角色
      verifyLogin();
   }
}

之后是使用了map中的containsKey方法,来判断role是否在ROLE_MAP中存在该role,如果不存在,还会使用keySet方法读取出ROLE_MAP中的key值,并报错。

之后如果是role不为UNKNOWN,就会进入verifyLogin()方法,进行登录校验。

public void verifyLogin() throws Exception {
   //未登录没有权限操作
   if (visitorId == null) {
      throw new NotLoggedInException("未登录,请登录后再操作!");
   }

   if (visitorId instanceof Number) {
      if (((Number) visitorId).longValue() <= 0) {
         throw new NotLoggedInException("未登录,请登录后再操作!");
      }
   } 
   else if (visitorId instanceof String) {
      if (StringUtil.isEmpty(visitorId, true)) {
         throw new NotLoggedInException("未登录,请登录后再操作!");
      }
   }
   else {
      throw new UnsupportedDataTypeException("visitorId 只能是 Long 或 String 类型!");
   }

}

其会对visitorId进行判断,是否为空,类型是否为long或string。如果不符合条件,会抛出对应的错误。

之后又获取了请求的方法,并verifyRole进行verifyRole()方法

RequestMethod method = config.getMethod();
verifyRole(table, method, role);//验证允许的角色

其传进去的参数为table, method, role

public void verifyRole(String table, RequestMethod method, String role) throws Exception {
   Log.d(TAG, "verifyRole  table = " + table + "; method = " + method + "; role = " + role);
   if (table != null) {
      if (method == null) {
         method = GET;
      }
      if (role == null) {
         role = UNKNOWN;
      }
      
      Map<RequestMethod, String[]> map = ACCESS_MAP.get(table);

      if (map == null || Arrays.asList(map.get(method)).contains(role) == false) {
         throw new IllegalAccessException(table + " 不允许 " + role + " 用户的 " + method.name() + " 请求!");
      }
   }
}

首先可以看到method默认为GET,role默认为UNKNOWN。

只有当map中含有该方法,且方法中包含对应role时,才允许该请求。

Arrays.asList()方法是将数组转化成List集合的方法。

之后会获取tVisitor的IdKey

String visitorIdkey = getVisitorIdKey(config);

接下来就是通过一个switch语句对role进行判断了

		switch (role) {
		case LOGIN://verifyRole通过就行
			break;
		case CONTACT:
		case CIRCLE:
			//TODO 做一个缓存contactMap<visitorId, contactArray>,提高[]:{}查询性能, removeAccessInfo时map.remove(visitorId)
			//不能在Visitor内null -> [] ! 否则会导致某些查询加上不需要的条件!
			List<Object> list = visitor.getContactIdList() == null
			? new ArrayList<Object>() : new ArrayList<Object>(visitor.getContactIdList());
			if (role == CIRCLE) {
				list.add(visitorId);
			}

			//key!{}:[] 或 其它没有明确id的条件 等 可以和key{}:list组合。类型错误就报错
			requestId = (Number) config.getWhere(visitorIdkey, true);//JSON里数值不能保证是Long,可能是Integer
			@SuppressWarnings("unchecked") 
			Collection<Object> requestIdArray = (Collection<Object>) config.getWhere(visitorIdkey + "{}", true);//不能是 &{}, |{} 不要传,直接{}
			if (requestId != null) {
				if (requestIdArray == null) {
					requestIdArray = new JSONArray();
				}
				requestIdArray.add(requestId);
			}

			if (requestIdArray == null) {//可能是@得到 || requestIdArray.isEmpty()) {//请求未声明key:id或key{}:[...]条件,自动补全
				config.putWhere(visitorIdkey+"{}", JSON.parseArray(list), true); //key{}:[]有效,SQLConfig里throw NotExistException
			} 
			else {//请求已声明key:id或key{}:[]条件,直接验证
				for (Object id : requestIdArray) {
					if (id == null) {
						continue;
					}
					if (id instanceof Number == false) {//不能准确地判断Long,可能是Integer
						throw new UnsupportedDataTypeException(table + ".id类型错误,id类型必须是Long!");
					}
					if (list.contains(Long.valueOf("" + id)) == false) {//Integer等转为Long才能正确判断。强转崩溃
						throw new IllegalAccessException(visitorIdkey + " = " + id + " 的 " + table
								+ " 不允许 " + role + " 用户的 " + method.name() + " 请求!");
					}
				}
			}
			break;
		case OWNER:
			if (config.getMethod() == RequestMethod.POST) {
				List<String> c = config.getColumn();
				List<List<Object>> ovs = config.getValues();
				if ( (c == null || c.isEmpty()) || (ovs == null || ovs.isEmpty()) ) {
					throw new IllegalArgumentException("POST 请求必须在Table内设置要保存的 key:value !");
				}

				int index = c.indexOf(visitorIdkey);
				if (index >= 0) {
					Object oid;
					for (List<Object> ovl : ovs) {
						oid = ovl == null || index >= ovl.size() ? null : ovl.get(index);
						if (oid == null || StringUtil.getString(oid).equals("" + visitorId) == false) {
							throw new IllegalAccessException(visitorIdkey + " = " + oid + " 的 " + table
									+ " 不允许 " + role + " 用户的 " + method.name() + " 请求!");
						}
					}
				}
				else {
					List<String> nc = new ArrayList<>(c);
					nc.add(visitorIdkey);
					config.setColumn(nc);

					List<List<Object>> nvs = new ArrayList<>();
					List<Object> nvl;
					for (List<Object> ovl : ovs) {
						nvl = ovl == null || ovl.isEmpty() ? new ArrayList<>() : new ArrayList<>(ovl);
						nvl.add(visitorId);
						nvs.add(nvl);
					}

					config.setValues(nvs);
				}
			}
			else {
				requestId = config.getWhere(visitorIdkey, true);//JSON里数值不能保证是Long,可能是Integer
				if (requestId != null && StringUtil.getString(requestId).equals(StringUtil.getString(visitorId)) == false) {
					throw new IllegalAccessException(visitorIdkey + " = " + requestId + " 的 " + table
							+ " 不允许 " + role + " 用户的 " + method.name() + " 请求!");
				}

				config.putWhere(visitorIdkey, visitorId, true);
			}
			break;
		case ADMIN://这里不好做,在特定接口内部判。 可以是  /get/admin + 固定秘钥  Parser#needVerify,之后全局跳过验证
			verifyAdmin();
			break;
		default://unknown,verifyRole通过就行
			break;
		}

就以OWNER来举例,首先会判断Method是否为RequestMethod.POST,会对列和值进行判断是否为空,为空则会抛出错误。

之后会使用indexOf方法对visitorIdkey进行查找,如果找到了,就会将visitorIdkey与visitorId进行对比,如不符合,抛出不允许请求的提示。

如果未找到,则会添加visitorIdkey和visitorId在对应的List中。最后添加进SQLconfig中。

如果是其他方法,就会通过getWhere获取visitorIdkey,并将其与visitorId进行对比,不一致的话,抛出不允许请求的提示。

猜你喜欢

转载自blog.csdn.net/qq_50861917/article/details/122018021