programing tip

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

itbloger 2020. 9. 9. 07:46
반응형

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


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

예를 들어 다음과 같이 사용되는 '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 바람직하지 않음)
  • At least in my Eclipse, I can't resolve a MethodSecurityEvaluationContext object

The differences are that we call the existing createEvaluationContext method and then add our custom root object. Finally I just returned an StandardEvaluationContext object type since MethodSecurityEvaluationContext would not resolve in the compiler (they are both from the same interface). This is the code that I now have in production.

Make MethodSecurityExpressionHandler use our custom root:

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;
    }
}

This replaces the default root by extending SecurityExpressionRoot. Here I've renamed hasRole to 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);
    }

}

Finally update securityContext.xml (and make sure it's referenced from your 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" />

Note: the @Secured annotation will not accept this override as it runs through a different validation handler. So, in the above xml I disabled them to prevent later confusion.

참고URL : https://stackoverflow.com/questions/6632982/how-to-create-custom-methods-for-use-in-spring-security-expression-language-anno

반응형