필터를 통과한 request는 보안이 마킹된 메소드를 실행할 때마다 MethodSecurityInterceptor의 검사를 받는다. 이를 설정하는 곳이 GlobalMethodSecurityConfiguration이다. 여기에 securedEnabled = true를 설정하면 @Secured로 설정된 권한을 체크하고, prePostEnabled = true로 설정하면, @PreAuthorize, @PreFilter, @PostAuthorize, @PostFilter로 설정된 권한을 체크한다.
MethodSecurityInterceptor에서 중요한 멤버는 아래 세가지이다.
Authentication 통행증만 가지고는 권한 체크를 충분히 했다고 볼 수가 없다. 보통, 어떤 객체의 값을 변경해야 하는 경우는 메소드에 들어오기 전에, 값을 조회하려고 하는 경우에는 값을 가져온 이후에 각각 접근 권한을 체크해 줘야 한다.
체크해야 할 대상이 한개라면 Pre/PostAuthorized로 체크를 하면 되지만, 대상이 복수개라면 보통은 리스트로 묶이기 때문에 대상을 filtering해서 들어가거나 넘겨야 한다.
물론, 메소드를 처리하는 중간에 권한을 검사해야 하는 경우도 있다. 이 경우는 Proxy 빈의 특징을 잘 파악해서 메서드 간에 권한 검사가 충분히 이루어지도록 annotation을 설계해서 처리할 수 있다.
public Object decide(
Authentication authentication,
Object object,
Collection<ConfigAttribute> config,
Object returnedObject
) throws AccessDeniedException {
Object result = returnedObject;
for (AfterInvocationProvider provider : this.providers) {
result = provider.decide(authentication, object, config, result);
}
return result;
}
public Object decide(
Authentication authentication,
Object object,
Collection<ConfigAttribute> config,
Object returnedObject
) throws AccessDeniedException {
PostInvocationAttribute postInvocationAttribute = findPostInvocationAttribute(config);
if (postInvocationAttribute == null) {
return returnedObject;
}
return this.postAdvice.after(authentication, (MethodInvocation) object, postInvocationAttribute,
returnedObject);
}
public Object after(
Authentication authentication,
MethodInvocation mi,
PostInvocationAttribute postAttr,
Object returnedObject
) throws AccessDeniedException {
PostInvocationExpressionAttribute pia = (PostInvocationExpressionAttribute) postAttr;
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication, mi);
Expression postFilter = pia.getFilterExpression();
Expression postAuthorize = pia.getAuthorizeExpression();
if (postFilter != null) {
if (returnedObject != null) {
returnedObject = this.expressionHandler.filter(returnedObject, postFilter, ctx);
}
}
this.expressionHandler.setReturnObject(returnedObject, ctx);
if (postAuthorize != null && !ExpressionUtils.evaluateAsBoolean(postAuthorize, ctx)) {
throw new AccessDeniedException("Access is denied");
}
return returnedObject;
}
참고