वसंत सुरक्षा के साथ जावा कोड में "hasRole" कैसे जांचें?


118

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

@PreAuthorize("hasRole('ROLE_USER')")

जावा कोड में इसे कैसे बनाएं? कुछ इस तरह :

if(somethingHere.hasRole("ROLE_MANAGER")) {
   layout.addComponent(new Button("Edit users"));
}

जवाबों:


70

स्प्रिंग सिक्योरिटी 3.0 में यह एपीआई है

SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)

इसके इस्तेमाल से पहले आपको रैपर को इंजेक्ट करना होगा।

SecurityContextHolderAwareRequestWrapper


53
जैसा कि आपका उत्तर बताया गया है, ऐसा लगता है कि विधि स्थिर है, हालांकि आपको एक SecurityContextHolderAwareRequestWrapperउदाहरण की आवश्यकता है । आप इसे समझा सकते हैं कि इसे कैसे प्राप्त किया जाए और उत्तर को थोड़ा और स्पष्ट किया जाए।
एक्सट्रीम बाइकर

3
मैं नियंत्रक में आवरण कैसे निकाल सकता हूं?
अल्फोंसो टियांडा

3
मैं SecurityContextHolderAwareRequestWrapper का उदाहरण कैसे प्राप्त कर सकता हूं?
gstackoverflow

2
Xtreme बाइकर सही है, आपको SecurityContextHolderAwareRequestWrapper वर्ग कैसे मिलता है? यह एक स्थिर वस्तु नहीं है।
इसे

5
यदि यह एक वेब ऐप था, जो ऐसा लगता है कि यह नहीं है, तो आप बस एक पैरामीटर के रूप में SecurityContextHolderAwareRequestWrapper जोड़ सकते हैं। और अगर यह एक वेब ऐप था, तो आप बस एक पैरामीटर के रूप में HttpServletRequest घोषित कर सकते हैं और isUserInRole
डेविड ब्रैडली

144

आप HttpServletRequest ऑब्जेक्ट के isUserInRole विधि का उपयोग कर सकते हैं।

कुछ इस तरह:

public String createForm(HttpSession session, HttpServletRequest request,  ModelMap   modelMap) {


    if (request.isUserInRole("ROLE_ADMIN")) {
        // code here
    }
}

मुझे लगता है कि परीक्षण करना आसान है
fego

1
लेकिन अगर मैंने अनुरोध नहीं किया है?
gstackoverflow

((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest()अनुरोध प्राप्त करने के बारे में क्या ? :)
पेट्र zजदस्क़ी

4
@ स्वतंत्र HttpServletRequest अनुरोध; ?
पास्कल

और यह भी एक स्प्रिंग एपीआई, सादा सर्वलेट कल्पना नहीं है! एक शर्म की बात है कि चुना हुआ जवाब नहीं है
gregfqt

67

UserDetails से प्राधिकरण खोजने के लिए लूप का उपयोग करने के बजाय आप कर सकते हैं:

Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
boolean authorized = authorities.contains(new SimpleGrantedAuthority("ROLE_ADMIN"));

2
एक बहुत अच्छा उत्तर, हालांकि ROLE_ADMIN दोहरे उद्धरण चिह्नों में होना चाहिए।
एरिका केन

6
यह बहुत जोखिम भरा है। ज्ञात हो कि GrantedAuthority कार्यान्वयन के दूसरे कार्यान्वयन पर स्विच करना (जैसे। JAAS, एक और प्राधिकरण संभावना जोड़कर) इस कोड को खराबी बना देगा। SimpleGrantedAuthority में समान () कार्यान्वयन देखें
Petr dsjezdský

47

आप सुरक्षा संदर्भ को पुनः प्राप्त कर सकते हैं और फिर उसका उपयोग कर सकते हैं:

    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.context.SecurityContext;
    import org.springframework.security.core.context.SecurityContextHolder;

    protected boolean hasRole(String role) {
        // get security context from thread local
        SecurityContext context = SecurityContextHolder.getContext();
        if (context == null)
            return false;

        Authentication authentication = context.getAuthentication();
        if (authentication == null)
            return false;

        for (GrantedAuthority auth : authentication.getAuthorities()) {
            if (role.equals(auth.getAuthority()))
                return true;
        }

        return false;
    }

SecurityContextHolder.getContext()कभी नहीं NULL, डॉक्स की जांच करें। इस प्रकार आप संदर्भ के जाँच से बच सकते हैं NULL
इम्तियाज शकील सिद्दीकी

14

आप नीचे के रूप में एक hasRole () विधि को लागू कर सकते हैं - (यह वसंत सुरक्षा पर परीक्षण किया गया है। 3.0.x अन्य संस्करणों के बारे में निश्चित नहीं है।)

  protected final boolean hasRole(String role) {
    boolean hasRole = false;
    UserDetails userDetails = getUserDetails();
    if (userDetails != null) {
      Collection<GrantedAuthority> authorities = userDetails.getAuthorities();
      if (isRolePresent(authorities, role)) {
        hasRole = true;
      }
    } 
    return hasRole;
  }
  /**
   * Get info about currently logged in user
   * @return UserDetails if found in the context, null otherwise
   */
  protected UserDetails getUserDetails() {
    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    UserDetails userDetails = null;
    if (principal instanceof UserDetails) {
      userDetails = (UserDetails) principal;
    }
    return userDetails;
  }
  /**
   * Check if a role is present in the authorities of current user
   * @param authorities all authorities assigned to current user
   * @param role required authority
   * @return true if role is present in list of authorities assigned to current user, false otherwise
   */
  private boolean isRolePresent(Collection<GrantedAuthority> authorities, String role) {
    boolean isRolePresent = false;
    for (GrantedAuthority grantedAuthority : authorities) {
      isRolePresent = grantedAuthority.getAuthority().equals(role);
      if (isRolePresent) break;
    }
    return isRolePresent;
  }

1
SecurityContextHolder.getContext().getAuthentication()पुनः प्राप्त कर सकते हैं null। शायद आप कुछ चेक जोड़ दें?
Mrusful

10

मैं इसका उपयोग कर रहा हूं:

@RequestMapping(method = RequestMethod.GET)
public void welcome(SecurityContextHolderAwareRequestWrapper request) {
    boolean b = request.isUserInRole("ROLE_ADMIN");
    System.out.println("ROLE_ADMIN=" + b);

    boolean c = request.isUserInRole("ROLE_USER");
    System.out.println("ROLE_USER=" + c);
}

8

आप AuthorityUtils वर्ग की कुछ मदद ले सकते हैं । एक-लाइनर के रूप में जाँच भूमिका:

if (AuthorityUtils.authorityListToSet(SecurityContextHolder.getContext().getAuthentication().getAuthorities()).contains("ROLE_MANAGER")) {
    /* ... */
}

कैविएट: यह भूमिका पदानुक्रम की जांच नहीं करता है, अगर ऐसा मौजूद है।


यही कारण है कि सबसे सरल समाधान है मुझे कई बार सूची की जांच करने की आवश्यकता है और एक बार कुछ जादुई सरल दिनचर्या के साथ इसे प्राप्त करना बहुत अच्छा है!
LeO

6

जोसेक के उत्तर का उपयोग आपकी सेवा की परत में नहीं किया जा सकता है, जहाँ आप HTTP अनुरोध के संदर्भ में वेब परत के साथ युग्मन पेश नहीं करना चाहते हैं। यदि आप सर्विस लेयर में भूमिकाओं को हल करते हुए देख रहे हैं, तो गोपी का उत्तर जाने का रास्ता है।

हालाँकि, यह थोड़ा लंबा है। अधिकारियों को प्रमाणीकरण से सीधे पहुँचा जा सकता है। इसलिए, यदि आप यह मान सकते हैं कि आपके पास कोई उपयोगकर्ता लॉग इन है, तो निम्न कार्य करता है:

/**
 * @return true if the user has one of the specified roles.
 */
protected boolean hasRole(String[] roles) {
    boolean result = false;
    for (GrantedAuthority authority : SecurityContextHolder.getContext().getAuthentication().getAuthorities()) {
        String userRole = authority.getAuthority();
        for (String role : roles) {
            if (role.equals(userRole)) {
                result = true;
                break;
            }
        }

        if (result) {
            break;
        }
    }

    return result;
}

6

अधिकांश उत्तर कुछ बिंदुओं को याद कर रहे हैं:

  1. भूमिका और अधिकार स्प्रिंग में समान नहीं हैं। अधिक जानकारी के लिए यहां देखें ।

  2. भूमिका नाम rolePrefix+ के बराबर हैं authority

  3. डिफ़ॉल्ट भूमिका उपसर्ग है ROLE_, हालांकि, यह विन्यास योग्य है। देखें यहाँ

इसलिए, यदि यह कॉन्फ़िगर किया गया है, तो भूमिका की उपसर्ग का सम्मान करने के लिए एक उचित भूमिका की जांच की आवश्यकता है।

दुर्भाग्य से, स्प्रिंग में भूमिका उपसर्ग अनुकूलन थोड़ा सा है, कई स्थानों पर डिफ़ॉल्ट उपसर्ग, ROLE_हार्डकोड किया गया है, लेकिन इसके अलावा, GrantedAuthorityDefaultsवसंत संदर्भ में एक प्रकार की बीन की जाँच की जाती है, और यदि यह मौजूद है, तो कस्टम भूमिका इसके उपसर्ग है। सम्मान किया गया है।

इन सभी जानकारियों को एक साथ लाते हुए, एक बेहतर भूमिका परीक्षक कार्यान्वयन कुछ इस तरह होगा:

@Component
public class RoleChecker {

    @Autowired(required = false)
    private GrantedAuthorityDefaults grantedAuthorityDefaults;

    public boolean hasRole(String role) {
        String rolePrefix = grantedAuthorityDefaults != null ? grantedAuthorityDefaults.getRolePrefix() : "ROLE_";
        return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
                .map(Authentication::getAuthorities)
                .map(Collection::stream)
                .orElse(Stream.empty())
                .map(GrantedAuthority::getAuthority)
                .map(authority -> rolePrefix + authority)
                .anyMatch(role::equals);
    }
}

3

अजीब तरह से, मुझे नहीं लगता कि इस समस्या का एक मानक समाधान है, क्योंकि वसंत-सुरक्षा अभिगम नियंत्रण अभिव्यक्ति आधारित है , जावा आधारित नहीं। आप DefaultMethodSecurityExpressionHandler के लिए स्रोत कोड देख सकते हैं कि क्या आप वहां कुछ उपयोग कर सकते हैं या नहीं।


तो आपका समाधान बीन के रूप में DefaultMethodSecurityExpressionHandler का उपयोग करना और अभिव्यक्ति पार्सर प्राप्त करना और इसे ईएल में जांचना है?
पिओटर ग्विजाडा

शायद यह काम नहीं करेगा, क्योंकि हैंडलर मेथडिनवोकेशन (जो आपके संदर्भ में आपके पास नहीं है) पर काम करता है। आपको शायद अपना खुद का बीन बनाने की ज़रूरत है जो कुछ ऐसा ही करता है, लेकिन मेथोड्वोकेशन संदर्भ का उपयोग किए बिना
शॉन पैट्रिक फ्लॉयड

2

देर से बेहतर तो कभी नहीं, मुझे मेरे 2 सेंट में डाल दिया।

जेएसएफ दुनिया में, मेरे प्रबंधित बीन के भीतर, मैंने निम्नलिखित कार्य किया:


HttpServletRequest req = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
SecurityContextHolderAwareRequestWrapper sc = new SecurityContextHolderAwareRequestWrapper(req, "");

जैसा कि ऊपर उल्लेख किया गया है, मेरी समझ यह है कि यह लंबे समय तक घुमावदार तरीके से किया जा सकता है:


Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserDetails userDetails = null;
if (principal instanceof UserDetails) {
    userDetails = (UserDetails) principal;
    Collection  authorities = userDetails.getAuthorities();
}

2

यह दूसरे छोर से सवाल पर आने की तरह है, लेकिन मुझे लगा कि मैं इसे फेंक दूंगा क्योंकि मुझे इसे खोजने के लिए वास्तव में इंटरनेट पर खुदाई करनी थी।

भूमिकाओं की जांच करने के बारे में बहुत सारी चीजें हैं, लेकिन बहुत कुछ नहीं कह रहा है कि आप वास्तव में क्या जाँच रहे हैं जब आप कहते हैं कि हैरोल ("ब्लाह")

HasRole वर्तमान में प्रमाणित प्रिंसिपल के लिए दिए गए अधिकारियों की जाँच करता है

तो वास्तव में जब आप देखते हैं hasRole ("blah") वास्तव में hasAuthority ("blah")

इस मामले में, मैंने देखा है कि आप एक क्लास के साथ ऐसा करते हैं कि इम्प्लीमेंट्स यूजरडेल जो कि getAuthorities नामक एक विधि को परिभाषित करता है। इसमें आप मूल रूप से new SimpleGrantedAuthority("some name")कुछ तर्क के आधार पर कुछ सूची में जोड़ देंगे । इस सूची में नाम है हैरो द्वारा बयान की जाँच की गई बातें।

मुझे लगता है कि इस संदर्भ में UserDetails ऑब्जेक्ट वर्तमान में प्रमाणित प्रिंसिपल है। कुछ जादू है जो प्रमाणीकरण प्रदाताओं और उसके आसपास और विशेष रूप से प्रमाणीकरण-प्रबंधक में होता है जो ऐसा करता है।


2
वसंत सुरक्षा 4.0 के रूप में यह hasRole("bla")अब के बराबर है hasAuthority("ROLE_bla")
लालनॉक्स

2

@Gouki जवाब सबसे अच्छा है!

बस कैसे वसंत वास्तव में ऐसा करते हैं की एक टिप।

वहाँ एक वर्ग में नामित किया है SecurityContextHolderAwareRequestWrapperजो लागू करता है ServletRequestWrapperवर्ग।

SecurityContextHolderAwareRequestWrapperओवरराइड isUserInRoleऔर खोज उपयोगकर्ता Authenticationअगर उपयोगकर्ता एक भूमिका है या नहीं (जो वसंत द्वारा किया जाता है) को खोजने के लिए।

SecurityContextHolderAwareRequestWrapper कोड इस प्रकार है:

    @Override
    public boolean isUserInRole(String role) {
        return isGranted(role);
    }

 private boolean isGranted(String role) {
        Authentication auth = getAuthentication();

        if( rolePrefix != null ) {
            role = rolePrefix + role;
        }

        if ((auth == null) || (auth.getPrincipal() == null)) {
            return false;
        }

        Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();

        if (authorities == null) {
            return false;
        }

        //This is the loop which do actual search
        for (GrantedAuthority grantedAuthority : authorities) {
            if (role.equals(grantedAuthority.getAuthority())) {
                return true;
            }
        }

        return false;
    }

2

नीचे यह दो एनोटेशन बराबर है, "hasRole" ऑटो उपसर्ग "ROLE_" जोड़ देगा। सुनिश्चित करें कि आपके पास सही एनोटेशन है। यह भूमिका UserDetailsService # loadUserByUsername में सेट है।

@PreAuthorize("hasAuthority('ROLE_user')")
@PreAuthorize("hasRole('user')")

फिर, आप जावा कोड में भूमिका प्राप्त कर सकते हैं।

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_user"))){
    System.out.println("user role2");
}

1

हमारी परियोजना में, हम एक भूमिका पदानुक्रम का उपयोग कर रहे हैं, जबकि ऊपर दिए गए अधिकांश उत्तर केवल एक विशिष्ट भूमिका के लिए जाँच करना है, अर्थात केवल दी गई भूमिका के लिए जाँच करेंगे, लेकिन उस भूमिका के लिए और पदानुक्रम नहीं।

इसके लिए एक समाधान:

@Component
public class SpringRoleEvaluator {

@Resource(name="roleHierarchy")
private RoleHierarchy roleHierarchy;

public boolean hasRole(String role) {
    UserDetails dt = AuthenticationUtils.getSessionUserDetails();

    for (GrantedAuthority auth: roleHierarchy.getReachableGrantedAuthorities(dt.getAuthorities())) {
        if (auth.toString().equals("ROLE_"+role)) {
            return true;
        }
    }
    return false;
}

RoleHierarchy को वसंत-सुरक्षा में एक बीन के रूप में परिभाषित किया गया है। xml।


1
या आप अपनी भूमिकाओं को ठीक से समझ सकते हैं: github.com/spring-projects/spring-security/issues/…
arctica

1

अपने उपयोगकर्ता मॉडल पर नीचे की तरह एक 'hasRole' विधि जोड़ें

public boolean hasRole(String auth) {
    for (Role role : roles) {
        if (role.getName().equals(auth)) { return true; }
    }
    return false;
}

मैं आमतौर पर यह जांचने के लिए उपयोग करता हूं कि क्या प्रमाणित उपयोगकर्ता की भूमिका व्यवस्थापक के अनुसार है

Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); // This gets the authentication
User authUser = (User) authentication.getPrincipal(); // This gets the logged in user
authUser.hasRole("ROLE_ADMIN") // This returns true or false

1

निम्नलिखित तरीकों का उपयोग करके उपयोगकर्ता रोल्स की जाँच की जा सकती है:

  1. SecurityContextHolder में कॉल स्टैटिक विधियों का उपयोग करना:

    Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && auth.getAuthorities().stream().anyMatch(role -> role.getAuthority().equals("ROLE_NAME"))) { //do something}

  2. HttpServletRequest का उपयोग करना

@GetMapping("/users")
public String getUsers(HttpServletRequest request) {
    if (request.isUserInRole("ROLE_NAME")) {
      
    }


0

Java8 की मदद से मेरा दृष्टिकोण, पासिंग कोमा से अलग की गई भूमिकाएं आपको सही या गलत बताएंगी

    public static Boolean hasAnyPermission(String permissions){
    Boolean result = false;
    if(permissions != null && !permissions.isEmpty()){
        String[] rolesArray = permissions.split(",");
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        for (String role : rolesArray) {
            boolean hasUserRole = authentication.getAuthorities().stream().anyMatch(r -> r.getAuthority().equals(role));
            if (hasUserRole) {
                result = true;
                break;
            }
        }
    }
    return result;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.