自定义权限评估器 Spring

Custom Permission Evaluator Spring

我想创建一个自定义权限评估器,以便使用自定义方法@PreAuthorize REST 端点。 我将 Spring Boot 1.5.3 与网络和安全启动器一起使用。

我的进一步用例是检查登录用户是否有权查看指定的 ID。

调用 REST 端点时出现以下错误:

org.springframework.expression.spel.SpelEvaluationException: EL1004E: Method call: Method hasPermission(null) cannot be found on org.springframework.security.access.expression.method.MethodSecurityExpressionRoot type

我的自定义权限评估器:

@Component
class CustomPermissionsEvaluator implements PermissionEvaluator {

    public boolean hasPermission(String id) {
        return id.equals("correct");
    }

    @Override
    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
        return false;
    }

    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
        return false;
    }
}

我的安全配置:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
class SecurityConfig extends GlobalMethodSecurityConfiguration {

    @Override
    public MethodSecurityExpressionHandler createExpressionHandler() {
        DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler = new DefaultMethodSecurityExpressionHandler();
        methodSecurityExpressionHandler.setPermissionEvaluator(new CompanyPermissionsEvaluator());
        return methodSecurityExpressionHandler;
    }
}

我的休息控制器:

@RestController
class RestControllerToProtect {

    @PreAuthorize("hasPermission(#id)")
    @GetMapping
    public String methodToProtect(String id) {
        return "Authenticated";
    }
}

堆栈跟踪:

org.springframework.expression.spel.SpelEvaluationException: EL1004E:
Method call: Method hasPermission(null) cannot be found on
org.springframework.security.access.expression.method.MethodSecurityExpressionRoot type

您不能在没有额外配置的情况下使用不属于 PermissionEvaluator 的重载方法(如果您想重新配置 PermissionEvaluator 模式,请参阅 答案)。

hasPermission 调用应默认匹配以下签名之一:

hasPermission(Authentication authentication, Object targetDomainObject, Object permission);

hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission);

示例:

public class CustomPermissionEvaluator implements PermissionEvaluator {

    private Logger log = LoggerFactory.getLogger(CustomPermissionEvaluator.class);

    @Override
    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
        CustomUserDetails customUserDetails = (CustomUserDetails) authentication.getPrincipal();
        AbstractEntity abstractEntity = (AbstractEntity) targetDomainObject;
        log.debug("User {} trying to access {}-{} with permission {}",
                customUserDetails.getUsername(),
                abstractEntity.getClass().getSimpleName(),
                abstractEntity.getId(),
                permission.toString());
        return false;
    }

    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
        CustomUserDetails customUserDetails = (CustomUserDetails) authentication.getPrincipal();
        log.debug("User {} trying to access {}-{} with permission {}",
                customUserDetails.getUsername(),
                targetType,
                targetId,
                permission.toString());
        return false;
    }
}

控制器:

@RestController
public class RestControllerToProtect {
    // passing targetDomainObject and permission, authentication is detected by SecurityExpressionRoot
    @PreAuthorize("hasPermission(#abstractEntity, 'create')")
    public String methodToProtect(@RequestBody AbstractEntity abstractEntity) {
        return "Authenticated";
    }
}

以下代码应该可以解决您的问题

检查 --> @customerPermissionsEvaluator。

@RestController
class RestControllerToProtect {

    @PreAuthorize("@customPermissionsEvaluator.hasPermission(#id)")
    @GetMapping
    public String methodToProtect(String id) {
        return "Authenticated";
    }
}