वसंत सुरक्षा अभिव्यक्ति भाषा एनोटेशन में उपयोग के लिए कस्टम तरीके कैसे बनाएं


92

मैं एक वर्ग बनाना चाहूंगा जो एनोटेशन के माध्यम से विधि-आधारित प्राधिकरण के लिए वसंत सुरक्षा अभिव्यक्ति भाषा में उपयोग के लिए कस्टम तरीके जोड़ता है।

उदाहरण के लिए, मैं 'customMethodReturningBoolean' जैसी एक कस्टम विधि बनाना चाहूंगा, जिसका उपयोग किसी तरह किया जा सके:

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

मेरा सवाल यह है। यदि यह संभव है, तो मुझे अपने कस्टम तरीकों को बनाने के लिए किस वर्ग को उपवर्गित करना चाहिए, मैं इसे स्प्रिंग एक्सएमएल कॉन्फ़िगरेशन फ़ाइलों में कॉन्फ़िगर करने के बारे में कैसे जाऊंगा और कोई मुझे इस तरह से उपयोग की जाने वाली कस्टम विधि का एक उदाहरण देगा?


1
मेरे पास अभी कोई उत्तर टाइप करने का समय नहीं है, लेकिन मैंने इस गाइड का पालन किया और इसने शानदार ढंग से काम किया: baeldung.com/ ... मैं स्प्रिंग समर 5.1.1 का उपयोग कर रहा हूं।
पॉल

जवाबों:


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 के सभी गुण एक्सेसर्स के बिना निजी हैं, इसलिए मैं उत्सुक था कि आपने बिना किसी बदसूरत प्रतिबिंब के कक्षा को कैसे बढ़ाया। धन्यवाद।
जोसेफ वास

1
आप का मतलब है TrustResolver, आदि? उन सभी DefaultMethodSecurityExpressionHandler देखें (कम से कम स्प्रिंग सुरक्षा 3.0 में) में setters है: static.springsource.org/spring-security/site/apidocs/org/...
sourcedelica

3
@ericacm आपको पैकेज-प्राइवेटMethodSecurityExpressionRoot होने के आसपास कैसे मिलता है ?
सी। रॉस

175

उल्लिखित तकनीकों में से कोई भी अब काम नहीं करेगा। ऐसा लगता है मानो उपयोगकर्ताओं को सिक्योरिटीएक्सप्रेशनरूट को ओवरराइड करने से रोकने के लिए स्प्रिंग बड़ी लंबाई से गुजरा है।

सुरक्षा एनोटेशन का उपयोग करने के लिए EDIT 11/19/14 सेटअप स्प्रिंग:

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

फिर अपने जेएसपी में ऐसा कुछ करें:

<sec:authorize access="@mySecurityService.hasPermission('special')">
    <input type="button" value="Special Button" />
</sec:authorize>

या किसी विधि को एनोटेट करें:

@PreAuthorize("@mySecurityService.hasPermission('special')")
public void doSpecialStuff() { ... }

इसके अतिरिक्त, आप अपने प्रमाणीकरणों में स्प्रिंग एक्सप्रेशन भाषा@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 विधि में, आप Authentication auth = SecurityContextHolder.getContext().getAuthentication();वर्तमान प्रमाणीकरण टोकन प्राप्त करने के लिए उपयोग कर सकते हैं ।
जेम्स वाटकिंस

2
आपके उत्तर के लिए धन्यवाद जेम्स। क्या मुझे स्प्रिंग कॉन्फ़िगरेशन फ़ाइल में mySecurityService को परिभाषित करना है?
वाह

2
आपको किसी भी XML फ़ाइल में mySecurityService को परिभाषित करने की आवश्यकता नहीं है यदि आपके पास उस सेवा के लिए पैकेज के लिए एक घटक-स्कैन सेटअप है। यदि आपके पास मिलान घटक-स्कैन नहीं है, तो आपको xml सेम परिभाषा का उपयोग करना होगा। @PreAuthorize org.springframework.security से आता है
जेम्स वाटकिंस

3
आपको बीन का नाम इस तरह निर्दिष्ट करना होगा: @Component ("mySecurityService") या @ नामांकित एनोटेशन का उपयोग करना।
जेम्स वाटकिंस

1
@ वीजेएस कृपया मेरे द्वारा किए गए संपादन को देखें। इन एनोटेशन का उपयोग करने के लिए आपको स्प्रिंग कॉन्फ़िगर करने की आवश्यकता होगी। मुझे आश्चर्य है कि इस महत्वपूर्ण लापता विवरण के बारे में किसी और ने शिकायत नहीं की :)
जेम्स वाटकिंस

14

धन्यवाद ericacm , लेकिन यह कुछ कारणों से काम नहीं करता है:

  • DefaultMethodSecurityExpressionHandler के गुण निजी हैं (प्रतिबिंब दृश्यता कीचड़ अवांछनीय है)
  • कम से कम मेरे ग्रहण में, मैं MethodSecurityEvaluationContext ऑब्जेक्ट को हल नहीं कर सकता

अंतर यह है कि हम मौजूदा createEvaluationContext विधि को कॉल करते हैं और फिर अपने कस्टम रूट ऑब्जेक्ट को जोड़ते हैं। अंत में मैंने अभी एक StandardEvaluationContext ऑब्जेक्ट प्रकार लौटाया क्योंकि MethodSecurityEvaluationContext कंपाइलर में हल नहीं होगा (वे दोनों एक ही इंटरफ़ेस से हैं)। यह वह कोड है जो अब मेरे पास उत्पादन में है।

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

}

अंत में 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" />

नोट: @ सुरक्षित एनोटेशन इस ओवरराइड को स्वीकार नहीं करेगा क्योंकि यह एक अलग सत्यापन हैंडलर के माध्यम से चलता है। इसलिए, उपरोक्त xml में मैंने बाद के भ्रम को रोकने के लिए उन्हें अक्षम कर दिया।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.