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进行对比,不一致的话,抛出不允许请求的提示。