security.hasPermission方法
public boolean hasPermission(String permission, GenericValue userLogin) {
if (userLogin == null) return false;
//查找出用户对应的安全组
Iterator<GenericValue> iterator = findUserLoginSecurityGroupByUserLoginId(userLogin.getString("userLoginId"));
GenericValue userLoginSecurityGroup = null;
//遍历每个组,查看是否这个组拥有这个权限
while (iterator.hasNext()) {
userLoginSecurityGroup = iterator.next();
if (securityGroupPermissionExists(userLoginSecurityGroup.getString("groupId"), permission)) return true;
}
return false;
}
而对于查找用户对应的组则很简单
collection = delegator.findByAnd("UserLoginSecurityGroup", UtilMisc.toMap("userLoginId", userLoginId), null);
查找表UserLoginSecurityGroup中userLoginid的信息
,再通过
collection = EntityUtil.filterByDate(collection, true);
过滤掉已经能够过期的组
而
securityGroupPermissionExists
方法也比较简单,是
从SecurityGroupPermission表读出一条permissionId=我们需要检查的权限groupId是当前组的id,如果结果不是null,就是存在这个权限了。
服务的授权代码
在ServiceDispatcher中(10.4版本代码,443行)代码
context = checkAuth(localName, context, modelService);
这是检查的代码,进入代码查看
,这里删除了一部分代码
private Map<String, Object> checkAuth(String localName,
Map<String, Object> context, ModelService origService)
throws ServiceAuthException, GenericServiceException {
DispatchContext dctx = this.getLocalContext(localName);
//这是处理service中的<permission-service service-name=""/>元素的。它会负责调用这个service,这个service需要返回一个Boolean hasPermission,来决定是否权限通过。
if (UtilValidate.isNotEmpty(origService.permissionServiceName)) {
Map<String, Object> permResp = origService.evalPermission(dctx,
context);
Boolean hasPermission = (Boolean) permResp.get("hasPermission");
if (hasPermission == null) {
throw new ServiceAuthException(
"ERROR: the permission-service ["
+ origService.permissionServiceName
+ "] did not return a result. Not running the service ["
+ origService.name + "]");
}
if (hasPermission.booleanValue()) {
context.putAll(permResp);
context = origService.makeValid(context, ModelService.IN_PARAM);
} else {
//很明显,未通过,赏它一段未通过的信息。
String message = (String) permResp.get("failMessage");
if (UtilValidate.isEmpty(message)) {
message = ServiceUtil.getErrorMessage(permResp);
}
if (UtilValidate.isEmpty(message)) {
message = "You do not have permission to invoke the service ["
+ origService.name + "]";
}
throw new ServiceAuthException(message);
}
} else {
//事件的权限处理origService.evalPermissions,进去look。
if (!origService.evalPermissions(dctx, context)) {
Locale l = (Locale) context.get("locale");
throw new ServiceAuthException(UtilProperties.getMessage(
"ServiceError", "Service.Auth", l)
+ "[" + origService.name + "]");
}
}
return context;
}
//没的神马东西,看来还得往里进,这里只要知道permissionGroups里面的是要检查的所有的权限内容。
如
<required-permissions join-type="AND">
<check-permission permission="TEST_VIEW" />
</required-permissions>
那么只有一个required-permissions,那permissionGroups只有一个对象(size=1)
public boolean evalPermissions(DispatchContext dctx, Map<String, ? extends Object> context) {
// old permission checking
if (this.containsPermissions()) {
for (ModelPermGroup group: this.permissionGroups) {
if (!group.evalPermissions(dctx, context)) {
return false;
}
}
return true;
} else {
return true;
}
}
//进入group.evalPermissions(dctx, context)方法
public boolean evalPermissions(DispatchContext dctx, Map<String, ? extends Object> context) {
//这里的permissions就是required-permission中的check-permission之类的子元素,类型是org.ofbiz.service.ModelPermission
if (UtilValidate.isNotEmpty(permissions)) {
boolean foundOne = false;
for (ModelPermission perm: permissions) {
//这里还要再调用evalPermission来处理权限
if (perm.evalPermission(dctx, context)) {
foundOne = true;
} else {
if (joinType.equals(PERM_JOIN_AND)) {
return false;
}
}
}
return foundOne;
} else {
return true;
}
}
//继续进入evalPermission
public boolean evalPermission(DispatchContext dctx, Map<String, ? extends Object> context) {
GenericValue userLogin = (GenericValue) context.get("userLogin");
Authorization authz = dctx.getAuthorization();
Security security = dctx.getSecurity();
//没登陆,肯定直接pass了。
if (userLogin == null) {
Debug.logInfo("Secure service requested with no userLogin object", module);
return false;
}
//有类型的,PERMISSION,简单的类型
switch (permissionType) {
case PERMISSION:
return evalAuthzPermission(authz, userLogin, context);
ENTITY_PERMISSION是permission+action的类型
case ENTITY_PERMISSION:
return evalEntityPermission(security, userLogin);
ROLE_MEMBER角色检查
case ROLE_MEMBER:
return evalRoleMember(userLogin);
PERMISSION_SERVICE使用服务方式处理的权限类型。,在required-permissions自然也可以包含permission-service
case PERMISSION_SERVICE:
return evalPermissionService(serviceModel, dctx, context);
default:
Debug.logWarning("Invalid permission type [" + permissionType + "] for permission named : " + nameOrRole + " on service : " + serviceModel.name, module);
简单的处理方式
private boolean evalAuthzPermission(Authorization authz, GenericValue userLogin, Map<String, ? extends Object> context) {
if (nameOrRole == null) {
Debug.logWarning("Null permission name passed for evaluation", module);
return false;
}
//authz是Authorization类,也没有必要再看下去了,这里是查找出这个用户当前所有的组,再看组里面有没有这个权限。
return authz.hasPermission(userLogin.getString("userLoginId"), nameOrRole, context);
}
return false;
}
}
再看ENTITY_PERMISSION类型的权限检查
它是调用
private boolean evalEntityPermission(Security security, GenericValue userLogin) {
if (nameOrRole == null) {
Debug.logWarning("Null permission name passed for evaluation", module);
return false;
}
if (action == null) {
Debug.logWarning("Null action passed for evaluation", module);
}
return security.hasEntityPermission(nameOrRole, action, userLogin);
}
实际上是通过Security 的hasEntityPermission方法类处理。
再其内部实际上可以看到的是(entity就是<check-permission permission="TEST_VIEW" />中的permission)
// always try _ADMIN first so that it will cache first, keeping the cache smaller
if (securityGroupPermissionExists(userLoginSecurityGroup.getString("groupId"), entity + "_ADMIN"))
return true;
if (securityGroupPermissionExists(userLoginSecurityGroup.getString("groupId"), entity + action))
return true;
它会对permission+action何permission+_ADMIN两者一起进行处理。
ROLE_MEMBER
evalEntityPermission方法,具体内容暂时不看了。
public boolean hasPermission(String permission, GenericValue userLogin) {
if (userLogin == null) return false;
//查找出用户对应的安全组
Iterator<GenericValue> iterator = findUserLoginSecurityGroupByUserLoginId(userLogin.getString("userLoginId"));
GenericValue userLoginSecurityGroup = null;
//遍历每个组,查看是否这个组拥有这个权限
while (iterator.hasNext()) {
userLoginSecurityGroup = iterator.next();
if (securityGroupPermissionExists(userLoginSecurityGroup.getString("groupId"), permission)) return true;
}
return false;
}
而对于查找用户对应的组则很简单
collection = delegator.findByAnd("UserLoginSecurityGroup", UtilMisc.toMap("userLoginId", userLoginId), null);
查找表UserLoginSecurityGroup中userLoginid的信息
,再通过
collection = EntityUtil.filterByDate(collection, true);
过滤掉已经能够过期的组
而
securityGroupPermissionExists
方法也比较简单,是
从SecurityGroupPermission表读出一条permissionId=我们需要检查的权限groupId是当前组的id,如果结果不是null,就是存在这个权限了。
服务的授权代码
在ServiceDispatcher中(10.4版本代码,443行)代码
context = checkAuth(localName, context, modelService);
这是检查的代码,进入代码查看
,这里删除了一部分代码
private Map<String, Object> checkAuth(String localName,
Map<String, Object> context, ModelService origService)
throws ServiceAuthException, GenericServiceException {
DispatchContext dctx = this.getLocalContext(localName);
//这是处理service中的<permission-service service-name=""/>元素的。它会负责调用这个service,这个service需要返回一个Boolean hasPermission,来决定是否权限通过。
if (UtilValidate.isNotEmpty(origService.permissionServiceName)) {
Map<String, Object> permResp = origService.evalPermission(dctx,
context);
Boolean hasPermission = (Boolean) permResp.get("hasPermission");
if (hasPermission == null) {
throw new ServiceAuthException(
"ERROR: the permission-service ["
+ origService.permissionServiceName
+ "] did not return a result. Not running the service ["
+ origService.name + "]");
}
if (hasPermission.booleanValue()) {
context.putAll(permResp);
context = origService.makeValid(context, ModelService.IN_PARAM);
} else {
//很明显,未通过,赏它一段未通过的信息。
String message = (String) permResp.get("failMessage");
if (UtilValidate.isEmpty(message)) {
message = ServiceUtil.getErrorMessage(permResp);
}
if (UtilValidate.isEmpty(message)) {
message = "You do not have permission to invoke the service ["
+ origService.name + "]";
}
throw new ServiceAuthException(message);
}
} else {
//事件的权限处理origService.evalPermissions,进去look。
if (!origService.evalPermissions(dctx, context)) {
Locale l = (Locale) context.get("locale");
throw new ServiceAuthException(UtilProperties.getMessage(
"ServiceError", "Service.Auth", l)
+ "[" + origService.name + "]");
}
}
return context;
}
//没的神马东西,看来还得往里进,这里只要知道permissionGroups里面的是要检查的所有的权限内容。
如
<required-permissions join-type="AND">
<check-permission permission="TEST_VIEW" />
</required-permissions>
那么只有一个required-permissions,那permissionGroups只有一个对象(size=1)
public boolean evalPermissions(DispatchContext dctx, Map<String, ? extends Object> context) {
// old permission checking
if (this.containsPermissions()) {
for (ModelPermGroup group: this.permissionGroups) {
if (!group.evalPermissions(dctx, context)) {
return false;
}
}
return true;
} else {
return true;
}
}
//进入group.evalPermissions(dctx, context)方法
public boolean evalPermissions(DispatchContext dctx, Map<String, ? extends Object> context) {
//这里的permissions就是required-permission中的check-permission之类的子元素,类型是org.ofbiz.service.ModelPermission
if (UtilValidate.isNotEmpty(permissions)) {
boolean foundOne = false;
for (ModelPermission perm: permissions) {
//这里还要再调用evalPermission来处理权限
if (perm.evalPermission(dctx, context)) {
foundOne = true;
} else {
if (joinType.equals(PERM_JOIN_AND)) {
return false;
}
}
}
return foundOne;
} else {
return true;
}
}
//继续进入evalPermission
public boolean evalPermission(DispatchContext dctx, Map<String, ? extends Object> context) {
GenericValue userLogin = (GenericValue) context.get("userLogin");
Authorization authz = dctx.getAuthorization();
Security security = dctx.getSecurity();
//没登陆,肯定直接pass了。
if (userLogin == null) {
Debug.logInfo("Secure service requested with no userLogin object", module);
return false;
}
//有类型的,PERMISSION,简单的类型
switch (permissionType) {
case PERMISSION:
return evalAuthzPermission(authz, userLogin, context);
ENTITY_PERMISSION是permission+action的类型
case ENTITY_PERMISSION:
return evalEntityPermission(security, userLogin);
ROLE_MEMBER角色检查
case ROLE_MEMBER:
return evalRoleMember(userLogin);
PERMISSION_SERVICE使用服务方式处理的权限类型。,在required-permissions自然也可以包含permission-service
case PERMISSION_SERVICE:
return evalPermissionService(serviceModel, dctx, context);
default:
Debug.logWarning("Invalid permission type [" + permissionType + "] for permission named : " + nameOrRole + " on service : " + serviceModel.name, module);
简单的处理方式
private boolean evalAuthzPermission(Authorization authz, GenericValue userLogin, Map<String, ? extends Object> context) {
if (nameOrRole == null) {
Debug.logWarning("Null permission name passed for evaluation", module);
return false;
}
//authz是Authorization类,也没有必要再看下去了,这里是查找出这个用户当前所有的组,再看组里面有没有这个权限。
return authz.hasPermission(userLogin.getString("userLoginId"), nameOrRole, context);
}
return false;
}
}
再看ENTITY_PERMISSION类型的权限检查
它是调用
private boolean evalEntityPermission(Security security, GenericValue userLogin) {
if (nameOrRole == null) {
Debug.logWarning("Null permission name passed for evaluation", module);
return false;
}
if (action == null) {
Debug.logWarning("Null action passed for evaluation", module);
}
return security.hasEntityPermission(nameOrRole, action, userLogin);
}
实际上是通过Security 的hasEntityPermission方法类处理。
再其内部实际上可以看到的是(entity就是<check-permission permission="TEST_VIEW" />中的permission)
// always try _ADMIN first so that it will cache first, keeping the cache smaller
if (securityGroupPermissionExists(userLoginSecurityGroup.getString("groupId"), entity + "_ADMIN"))
return true;
if (securityGroupPermissionExists(userLoginSecurityGroup.getString("groupId"), entity + action))
return true;
它会对permission+action何permission+_ADMIN两者一起进行处理。
ROLE_MEMBER
evalEntityPermission方法,具体内容暂时不看了。