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


92

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

예를 들어 다음과 같이 사용되는 'customMethodReturningBoolean'과 같은 사용자 지정 메서드를 만들고 싶습니다.

  @PreAuthorize("customMethodReturningBoolean()")
  public void myMethodToSecure() { 
    // whatever
  }

제 질문은 이것입니다. 가능하다면 사용자 지정 메서드를 생성하기 위해 어떤 클래스를 하위 클래스로 지정해야합니까? 스프링 xml 구성 파일에서 구성하는 방법에 대해 설명하고 누군가 이러한 방식으로 사용되는 사용자 지정 메서드의 예를 제공 할 수 있습니까?


1
지금은 답을 입력 할 시간이 없지만이 가이드를 따랐고 훌륭하게 작동했습니다. baeldung.com/… 저는 Spring Security 5.1.1을 사용하고 있습니다.
Paul

답변:


35

두 개의 클래스를 하위 클래스로 분류해야합니다.

먼저 새 메서드 표현식 핸들러를 설정합니다.

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

흠, 좋은 생각처럼 들리지만 DefaultMethodSecurityExpressionHandler의 모든 속성은 접근자가없는 비공개이므로 추악한 반영없이 클래스를 확장하는 방법이 궁금했습니다. 감사.
Joseph Lust

1
trustResolver 등을 의미합니까? 그것들은 모두 DefaultMethodSecurityExpressionHandler에 setter를 가지고 있습니다 (적어도 Spring Security 3.0에서는) 참조 : static.springsource.org/spring-security/site/apidocs/org/…
sourcedelica

3
@ericacm 패키지 전용MethodSecurityExpressionRoot 이 되려면 어떻게해야 합니까?
C. Ross

175

언급 된 기술 중 어느 것도 더 이상 작동하지 않습니다. 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) { ... }

6
hasPermission 메소드에서 @Bosh를 사용 Authentication auth = SecurityContextHolder.getContext().getAuthentication();하면 현재 인증 토큰을 가져올 수 있습니다 .
James Watkins 2013 년

2
답변 해 주셔서 감사합니다. 스프링 설정 파일에 mySecurityService를 정의해야합니까?
WowBow

2
서비스가있는 패키지에 대한 구성 요소 스캔 설정이있는 경우 XML 파일에서 mySecurityService를 정의 할 필요가 없습니다. 일치하는 구성 요소 스캔이 없으면 xml 빈 정의를 사용해야합니다. @PreAuthorize는 org.springframework.security에서 온다
제임스 왓킨스에게

3
@Component ( "mySecurityService")와 같이 어노테이션에 Bean의 이름을 지정하거나 @Named 어노테이션을 사용해야 할 수 있습니다.
James Watkins 2013

1
@VJS 내가 만든 편집을 참조하십시오. 이러한 주석을 사용하려면 spring을 구성해야합니다. 나는 놀랄 아무도 다른 :)이 중요한 누락 된 세부 사항에 대해 불평하지거야
제임스 왓킨스에게

14

감사합니다 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에서 나중에 혼란을 방지하기 위해 비활성화했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.