[java] 스프링 보안 표현 언어 주석에서 사용할 사용자 지정 메서드를 만드는 방법

주석을 통한 메서드 기반 인증을 위해 스프링 보안 표현 언어에서 사용할 사용자 지정 메서드를 추가하는 클래스를 만들고 싶습니다.

예를 들어 다음과 같이 사용되는 ‘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에서 나중에 혼란을 방지하기 위해 비활성화했습니다.


답변