주석을 통한 메서드 기반 인증을 위해 스프링 보안 표현 언어에서 사용할 사용자 지정 메서드를 추가하는 클래스를 만들고 싶습니다.
예를 들어 다음과 같이 사용되는 ‘customMethodReturningBoolean’과 같은 사용자 지정 메서드를 만들고 싶습니다.
@PreAuthorize("customMethodReturningBoolean()")
public void myMethodToSecure() {
// whatever
}
제 질문은 이것입니다. 가능하다면 사용자 지정 메서드를 생성하기 위해 어떤 클래스를 하위 클래스로 지정해야합니까? 스프링 xml 구성 파일에서 구성하는 방법에 대해 설명하고 누군가 이러한 방식으로 사용되는 사용자 지정 메서드의 예를 제공 할 수 있습니까?
답변
두 개의 클래스를 하위 클래스로 분류해야합니다.
먼저 새 메서드 표현식 핸들러를 설정합니다.
<global-method-security>
<expression-handler ref="myMethodSecurityExpressionHandler"/>
</global-method-security>
myMethodSecurityExpressionHandler
의 하위 클래스 DefaultMethodSecurityExpressionHandler
를 재정의 createEvaluationContext()
하는 하위 클래스가 MethodSecurityExpressionRoot
됩니다 MethodSecurityEvaluationContext
.
예를 들면 :
@Override
public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) {
MethodSecurityEvaluationContext ctx = new MethodSecurityEvaluationContext(auth, mi, parameterNameDiscoverer);
MethodSecurityExpressionRoot root = new MyMethodSecurityExpressionRoot(auth);
root.setTrustResolver(trustResolver);
root.setPermissionEvaluator(permissionEvaluator);
root.setRoleHierarchy(roleHierarchy);
ctx.setRootObject(root);
return ctx;
}
답변
언급 된 기술 중 어느 것도 더 이상 작동하지 않습니다. Spring은 사용자가 SecurityExpressionRoot를 재정의하는 것을 방지하기 위해 많은 노력을 기울인 것처럼 보입니다.
11/19/14 설정 Spring을 수정하여 보안 주석을 사용하십시오.
<beans ... xmlns:sec="http://www.springframework.org/schema/security" ... >
...
<sec:global-method-security pre-post-annotations="enabled" />
다음과 같이 빈을 만듭니다.
@Component("mySecurityService")
public class MySecurityService {
public boolean hasPermission(String key) {
return true;
}
}
그런 다음 jsp에서 다음과 같이하십시오.
<sec:authorize access="@mySecurityService.hasPermission('special')">
<input type="button" value="Special Button" />
</sec:authorize>
또는 메소드에 주석을 추가하십시오.
@PreAuthorize("@mySecurityService.hasPermission('special')")
public void doSpecialStuff() { ... }
또한 주석 에서 Spring Expression Language@PreAuthorize
를 사용하여 현재 인증 및 메소드 인수에 액세스 할 수 있습니다 .
예를 들면 :
@Component("mySecurityService")
public class MySecurityService {
public boolean hasPermission(Authentication authentication, String foo) { ... }
}
그런 다음 @PreAuthorize
새 메소드 서명과 일치하도록 업데이트하십시오 .
@PreAuthorize("@mySecurityService.hasPermission(authentication, #foo)")
public void doSpecialStuff(String foo) { ... }
답변
감사합니다 ericacm ,하지만 몇 가지 이유로 작동하지 않습니다.
- DefaultMethodSecurityExpressionHandler 의 속성 은 비공개입니다 (반사 가시성 kludges 바람직하지 않음)
- 적어도 내 Eclipse에서는 MethodSecurityEvaluationContext 개체를 해결할 수 없습니다.
차이점은 기존 createEvaluationContext 메서드를 호출 한 다음 사용자 지정 루트 개체를 추가 한다는 것 입니다. 마지막으로 MethodSecurityEvaluationContext가 컴파일러에서 확인되지 않기 때문에 StandardEvaluationContext 개체 유형을 반환했습니다 (둘 다 동일한 인터페이스에서 생성됨). 이것이 제가 현재 생산중인 코드입니다.
확인 MethodSecurityExpressionHandler는 우리의 사용자 루트를 사용합니다 :
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
// parent constructor
public CustomMethodSecurityExpressionHandler() {
super();
}
/**
* Custom override to use {@link CustomSecurityExpressionRoot}
*
* Uses a {@link MethodSecurityEvaluationContext} as the <tt>EvaluationContext</tt> implementation and
* configures it with a {@link MethodSecurityExpressionRoot} instance as the expression root object.
*/
@Override
public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) {
// due to private methods, call original method, then override it's root with ours
StandardEvaluationContext ctx = (StandardEvaluationContext) super.createEvaluationContext(auth, mi);
ctx.setRootObject( new CustomSecurityExpressionRoot(auth) );
return ctx;
}
}
이것은 SecurityExpressionRoot 를 확장하여 기본 루트를 대체합니다 . 여기에서 hasRole의 이름을 hasEntitlement로 변경했습니다.
public class CustomSecurityExpressionRoot extends SecurityExpressionRoot {
// parent constructor
public CustomSecurityExpressionRoot(Authentication a) {
super(a);
}
/**
* Pass through to hasRole preserving Entitlement method naming convention
* @param expression
* @return boolean
*/
public boolean hasEntitlement(String expression) {
return hasRole(expression);
}
}
마지막으로 securityContext.xml을 업데이트하십시오 (그리고 applcationContext.xml에서 참조되는지 확인하십시오).
<!-- setup method level security using annotations -->
<security:global-method-security
jsr250-annotations="disabled"
secured-annotations="disabled"
pre-post-annotations="enabled">
<security:expression-handler ref="expressionHandler"/>
</security:global-method-security>
<!--<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">-->
<bean id="expressionHandler" class="com.yourSite.security.CustomMethodSecurityExpressionHandler" />
참고 : @Secured 주석은 다른 유효성 검사 처리기를 통해 실행되므로이 재정의를 허용하지 않습니다. 따라서 위의 xml에서 나중에 혼란을 방지하기 위해 비활성화했습니다.