Spring Security ile Java Kodunda "hasRole" nasıl kontrol edilir?


118

Java Kodunda kullanıcı yetkisi veya izni nasıl kontrol edilir? Örneğin, role bağlı olarak kullanıcı için düğmeyi göstermek veya gizlemek istiyorum. Gibi ek açıklamalar var:

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

Java kodunda nasıl yapılır? Gibi bir şey :

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

Yanıtlar:


70

Spring Security 3.0 bu API'ye sahiptir

SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)

Kullanmadan önce sargıyı enjekte etmeniz gerekecek.

SecurityContextHolderAwareRequestWrapper


53
Cevabınız belirtildiği gibi, yöntem statik gibi görünüyor, ancak bir SecurityContextHolderAwareRequestWrapperörneğe ihtiyacınız var . Nasıl elde edileceğini açıklayarak ve cevabın kendisini biraz daha netleştirerek geliştirebilirsiniz.
Xtreme Biker

3
Kontrolördeki sarmalayıcıyı nasıl alabilirim?
Alfonso Shariq

3
SecurityContextHolderAwareRequestWrapper örneğini nasıl edinebilirim?
gstackoverflow

2
Xtreme Biker haklı, SecurityContextHolderAwareRequestWrapper sınıfını nasıl elde edersiniz? Statik bir nesne değil.
deneyin

5
Bu, öyle görünmeyen bir web uygulamasıysa, SecurityContextHolderAwareRequestWrapper'ı parametre olarak ekleyebilirsiniz. Ve bir web uygulaması olsaydı, HttpServletRequest'i bir parametre olarak ilan edebilir ve isUserInRole'u çağırabilirdiniz
David Bradley

144

HttpServletRequest nesnesinin isUserInRole yöntemini kullanabilirsiniz.

gibi bir şey:

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


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

sanırım test etmesi daha kolay
fego

1
ama istemezsem?
gstackoverflow

((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest()İsteği almaya ne dersiniz ? :)
Petr Újezdský

4
@Autowired HttpServletRequest isteği; ?
Pascal

Ve bu bir Spring API bile değil, düz Servlet spesifikasyonu! Seçilmiş cevap bu değil utanç verici
gregfqt

67

UserDetails'ten yetkiyi bulmak için bir döngü kullanmak yerine şunları yapabilirsiniz:

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

2
Çok daha güzel bir cevap, ancak ROLE_ADMIN çift tırnak içinde olmalıdır.
Erica Kane

6
Bu çok riskli. GrantedAuthority uygulamasının başka bir uygulamasına geçmenin (örneğin, başka bir yetkilendirme olasılığı ekleyerek JAAS) bu kodun hatalı çalışmasına neden olacağını unutmayın.
SimpleGrantedAuthority'deki

47

Güvenlik bağlamını alabilir ve ardından bunu kullanabilirsiniz:

    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()asla NULL, belgeleri kontrol et. Böylece içeriğin varlığını kontrol etmekten kaçınabilirsiniz NULL.
Imtiaz Shakil Siddique

14

Bir hasRole () yöntemini aşağıdaki gibi uygulayabilirsiniz - (Bu, yay güvenliği 3.0.x üzerinde test edilmiştir, diğer sürümlerden emin değil.)

  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()alabilir null. Belki biraz çek eklersiniz?
Mrusful

10

Bunu kullanıyorum:

@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 sınıfından yardım alabilirsiniz . Rolü tek satırlık olarak kontrol etmek:

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

Uyarı: Bu, varsa rol hiyerarşisini kontrol etmez.


Bu en basit çözüm çünkü Listeyi birkaç kez kontrol etmem gerekiyor ve bazı sihirli basit rutinlerle onu bir kez getirmek harika!
LeO

6

JoseK'nin yanıtı, hizmet katmanınızda, referanstan HTTP isteğine web katmanı ile bir bağlantı eklemek istemediğinizde kullanılamaz. Hizmet katmanındayken rolleri çözmeyi düşünüyorsanız, Gopi'nin cevabı gitmenin yoludur.

Ancak, biraz uzun soluklu. Yetkililere, Kimlik Doğrulamadan erişilebilir. Dolayısıyla, oturum açmış bir kullanıcı olduğunu varsayabiliyorsanız, aşağıdakileri yapar:

/**
 * @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

Cevapların çoğunda bazı noktalar eksik:

  1. Baharda rol ve otorite aynı şey değildir. Daha fazla ayrıntı için buraya bakın.

  2. Rol adları rolePrefix+ 'ya eşittir authority.

  3. Varsayılan rol öneki ROLE_, ancak yapılandırılabilir. Buraya bakın .

Bu nedenle, uygun bir rol denetimi, yapılandırılmışsa rol önekine uymalıdır.

Ne yazık ki, Spring'deki rol öneki özelleştirmesi biraz karmaşıktır, birçok yerde varsayılan önek ROLE_kodlanmıştır, ancak buna ek olarak GrantedAuthorityDefaults, Bahar bağlamında bir fasulye türü kontrol edilir ve varsa, özel rol öneki saygı duyulur.

Tüm bu bilgileri bir araya getirdiğimizde, daha iyi bir rol denetleyicisi uygulaması şöyle bir şey olabilir:

@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

Garip bir şekilde, bahar güvenlikli erişim kontrolü java tabanlı değil ifade tabanlı olduğundan , bu soruna standart bir çözüm olduğunu düşünmüyorum . Orada yaptıkları bir şeyi yeniden kullanıp kullanamayacağınızı görmek için DefaultMethodSecurityExpressionHandler için kaynak kodunu kontrol edebilirsiniz.


Öyleyse çözümünüz, Bean olarak DefaultMethodSecurityExpressionHandler'ı kullanmak ve ifade ayrıştırıcısını alıp EL'de kontrol etmek mi?
Piotr Gwiazda

bu muhtemelen işe yaramayacaktır, çünkü işleyici yöntem çağrıları üzerinde çalışmaktadır (sizin bağlamınızda sahip olmadığınız). muhtemelen benzer bir şey yapan kendi fasulyenizi yaratmanız gerekir, ancak bir yöntem sorusu bağlamı kullanmadan
Sean Patrick Floyd

2

Asla geç kalması iyidir, 2 sent değerimi koymama izin verin.

JSF dünyasında, yönetilen fasulyemde şunları yaptım:


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

Yukarıda bahsedildiği gibi, benim anlayışım, aşağıdaki gibi uzun soluklu bir şekilde yapılabileceğidir:


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

2

Bu, soruya diğer taraftan geliyor, ancak bunu bulmak için gerçekten internette kazmak zorunda olduğum için onu ekleyeceğimi düşündüm.

Rolleri nasıl kontrol edeceğiniz hakkında pek çok şey var ama hasRole ("blah") derken aslında neyi kontrol ettiğinizi söylemiyor

HasRole, şu anda kimliği doğrulanmış müdür için verilen yetkileri kontrol eder

Yani gerçekten hasRole ("blah") ifadesini gördüğünüzde hasAuthority ("blah") anlamına gelir .

Gördüğüm durumda, bunu getAuthorities adında bir yöntemi tanımlayan UserDetails Uygulayan bir sınıfla yapıyorsunuz. Burada, temelde new SimpleGrantedAuthority("some name")bazı mantığa dayalı olarak bir listeye bazılarını ekleyeceksiniz . Bu listedeki isimler hasRole ifadeleri tarafından kontrol edilen şeylerdir.

Sanırım bu bağlamda UserDetails nesnesi şu anda kimliği doğrulanmış asıl öğe. Kimlik doğrulama sağlayıcılarında ve çevresinde ve daha özel olarak bunu gerçekleştiren kimlik doğrulama yöneticisinde bazı sihir var.


2
Spring Security 4.0 itibariyle bu hasRole("bla")artık eşittir hasAuthority("ROLE_bla").
lanoxx

2

@Gouki yanıtı en iyisidir!

Baharın bunu nasıl yaptığına dair bir ipucu.

Sınıfı SecurityContextHolderAwareRequestWrapperuygulayan bir ServletRequestWrappersınıf var.

SecurityContextHolderAwareRequestWrapperGeçersiz kılar isUserInRoleve arama kullanıcı Authenticationkullanıcı bir rolü vardır olmadığını (Bahar tarafından yönetilen) bulmak için.

SecurityContextHolderAwareRequestWrapper kod şu şekildedir:

    @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

Aşağıdaki bu iki açıklama eşittir, "hasRole" otomatik olarak "ROLE_" önekini ekleyecektir. Doğru açıklamaya sahip olduğunuzdan emin olun. Bu rol UserDetailsService # loadUserByUsername içerisinde ayarlanır.

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

daha sonra, java kodunda rol alabilirsiniz.

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

1

Projemizde, bir rol hiyerarşisi kullanıyoruz, oysa yukarıdaki cevapların çoğu sadece belirli bir rolü kontrol etmeyi amaçlıyor, yani sadece verilen rolü kontrol ediyor, ancak o rolü ve hiyerarşiyi yükseltmiyor.

Bunun için bir çözüm:

@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, spring-security.xml'de bir fasulye olarak tanımlanır.


1
Veya rollerinizi doğru şekilde doldurabilirsiniz
arctica

1

Kullanıcı modelinize aşağıdaki gibi bir 'hasRole' yöntemi ekleyin

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

Bunu genellikle kimliği doğrulanmış kullanıcının aşağıdaki gibi yönetici rolüne sahip olup olmadığını kontrol etmek için kullanırım

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

Kullanıcı Rolleri aşağıdaki yöntemler kullanılarak kontrol edilebilir:

  1. SecurityContextHolder'da çağrı statik yöntemlerini kullanma:

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

  2. HttpServletRequest'i kullanma

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


0

Java8 yardımıyla Yaklaşımım, Koma ile ayrılmış rolleri geçmek size doğru veya yanlış verecektir

    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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.