Різниця між роллю та наданим авторитетом у весняній безпеці


227

У Spring Security є концепції та реалізації, такі як GrantedAuthorityінтерфейс для отримання повноважень щодо авторизації / контролю доступу.

Я хотів би це зробити дозволеними операціями, такими як createSubUsers або deleteAccounts , які я дозволю адміністратору (з роллю ROLE_ADMIN).

Я заплутався, коли навчальні матеріали / демонстрації я бачу в Інтернеті. Я намагаюся зв’язати те, що я прочитав, але думаю, що ми ставимось до цих двох взаємозамінно.

Я бачу, що hasRoleспоживає GrantedAuthorityрядок? Я, безумовно, роблю це неправильно в розумінні. Що це за концептуальна безпека весни?

Як я можу зберігати роль користувача, окремо від влади для цієї ролі?

Я також дивлюся на org.springframework.security.core.userdetails.UserDetailsінтерфейс, який використовується у DAO, на який посилається постачальник аутентифікації, який споживає User(відмітьте останню GrantedAuthority):

public User(String username, 
            String password, 
            boolean enabled, 
            boolean accountNonExpired,
            boolean credentialsNonExpired, 
            boolean accountNonLocked, 
            Collection<? extends GrantedAuthority> authorities)

Або є якийсь інший спосіб диференціювати інші два? Або це не підтримується, і ми маємо зробити своє?

Відповіді:


365

Подумайте про GrantedAuthority як про "дозвіл" або "право". Ці "дозволи" (як правило) виражаються у вигляді рядків ( getAuthority()методом). Ці рядки дозволяють ідентифікувати дозволи та дозволяти вашим виборцям вирішувати, чи дозволяють їм доступ до чогось.

Ви можете надати різні GrantedAuthoritys (дозволи) користувачам, ввівши їх у контекст безпеки. Зазвичай ви робите це, застосовуючи власну UserDetailsService, яка повертає реалізацію UserDetails, яка повертає необхідні GrantedAuthorities.

Ролі (як вони використовуються у багатьох прикладах) - це лише "дозволи" із умовою іменування, який говорить про те, що роль - це GrantedAuthority, який починається з префікса ROLE_. Більше нічого немає. Роль - це лише GrantedAuthority - «дозвіл» - «право». Ви бачите багато місць у захисті весни, де роль з його ROLE_префіксом обробляється спеціально, як, наприклад, у RoleVoter, де ROLE_префікс використовується як за замовчуванням. Це дозволяє надати імена ролей без ROLE_префікса. До Весняної безпеки 4 цього особливого поводження з "ролями" не дотримувалися дуже послідовно, і повноваження та ролі часто трактувалися однаково (як ви, наприклад,hasAuthority()hasRole()). З Spring Security 4 обробка ролей є більш послідовною, і код, який стосується "ролей" (наприклад RoleVoter, hasRoleвираз тощо), завжди додає ROLE_для вас префікс. Так hasAuthority('ROLE_ADMIN')означає те саме, що hasRole('ADMIN')тому, що ROLE_префікс додається автоматично. Докладніші відомості див. У весняному посібнику з міграції щодо безпеки 3 до 4 .

Але все-таки: роль - це лише авторитет зі спеціальним ROLE_префіксом. Так у Spring безпека 3 @PreAuthorize("hasRole('ROLE_XYZ')")така сама, як @PreAuthorize("hasAuthority('ROLE_XYZ')")і у Spring схожість 4 @PreAuthorize("hasRole('XYZ')")така сама, як у Spring Spring 4 @PreAuthorize("hasAuthority('ROLE_XYZ')").

Що стосується Вашого випадку використання:

Користувачі мають ролі і ролі можуть виконувати певні операції.

Ви можете отримати GrantedAuthoritiesдля ролей, яким належить користувач, і операцій, які може виконувати роль. GrantedAuthoritiesДля ролі префікса ROLE_і операції мають префікс OP_. Прикладом операції влади може бути OP_DELETE_ACCOUNT, OP_CREATE_USER, та OP_RUN_BATCH_JOBт.д. Ролі можуть бути ROLE_ADMIN, ROLE_USER, та ROLE_OWNERт.д.

Можливо, ваші сутності реалізують GrantedAuthorityяк у цьому прикладі (псевдокод):

@Entity
class Role implements GrantedAuthority {
    @Id
    private String id;

    @ManyToMany
    private final List<Operation> allowedOperations = new ArrayList<>();

    @Override
    public String getAuthority() {
        return id;
    }

    public Collection<GrantedAuthority> getAllowedOperations() {
        return allowedOperations;
    }
}

@Entity
class User {
    @Id
    private String id;

    @ManyToMany
    private final List<Role> roles = new ArrayList<>();

    public Collection<Role> getRoles() {
        return roles;
    }
}

@Entity
class Operation implements GrantedAuthority {
    @Id
    private String id;

    @Override
    public String getAuthority() {
        return id;
    }
}

Ідентифікатори ролей та операцій, які ви створюєте у вашій базі даних, будуть представленням GrantedAuthority, наприклад ROLE_ADMIN, OP_DELETE_ACCOUNTтощо. Коли користувач має автентифікацію, переконайтесь, що всі GrantedAuthorities усіх його ролей та відповідні операції повертаються з UserDetails.getAuthorities () метод.

Приклад: адмін роль з ідентифікатором ROLE_ADMINмає операції OP_DELETE_ACCOUNT, OP_READ_ACCOUNT, OP_RUN_BATCH_JOBпокладені на нього. Роль користувача з id ROLE_USERмає операцію OP_READ_ACCOUNT.

Якщо адмін журнали в результуючому контексті безпеки буде мати GrantedAuthorities: ROLE_ADMIN, OP_DELETE_ACCOUNT, OP_READ_ACCOUNT,OP_RUN_BATCH_JOB

Якщо користувач входить в систему , він буде мати: ROLE_USER,OP_READ_ACCOUNT

UserDetailsService піклується про збирання всіх ролей та всіх операцій цих ролей та надання їх доступним методом getAuthorities () у поверненому екземплярі UserDetails.


2
Дякую! Я всюди шукав, чому "hasRole ('rolename')" не працював весною 4 -> Їх документація не дуже швидко проскакувала. Просто швидке "пошук і заміна", і я знову на шляху!
Jørgen Skår Fischer

12
Це чудова відповідь. Одна річ , щоб зробити ясним , щоб пояснити трохи по- різному, hasRole('xyz')в Spring Security 4 очікує , що ви маєте ROLE_ префікс а hasAuthority('xyz')не очікує , що префікс і оцінює саме те , що передається. Я використав це рішення, але працює з проблемами з hasRole('OP_MY_PERMISSION')так ROLE_ був потрібен префікс. Натомість я повинен був використовувати те, hasAuthority('OP_MY_PERMISSION')що не мав префікса.
randal4

@james ви можете подивитися на це питання stackoverflow.com/questions/41500031 / ...
Saurabh Кумар

1
У JSTL springframework.org/security/tags <sec:authorize access="hasRole('ADMIN')">те саме, що<sec:authorize access="hasRole('ROLE_ADMIN')">
Alex78191

1
Так. OP_ - лише довільний префікс. ROLE_ має своє особливе значення у деяких весняних реалізаціях.
Джеймс

9

AFAIK GrantedAuthority та ролі однакові у безпеці весни. Рядок getAuthority () GrantedAuthority - це роль (відповідно до реалізації за замовчуванням SimpleGrantedAuthority).

Ви можете скористатися ієрархічними ролями

<bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
    <constructor-arg ref="roleHierarchy" />
</bean>
<bean id="roleHierarchy"
        class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
    <property name="hierarchy">
        <value>
            ROLE_ADMIN > ROLE_createSubUsers
            ROLE_ADMIN > ROLE_deleteAccounts 
            ROLE_USER > ROLE_viewAccounts
        </value>
    </property>
</bean>

Не точний золь, який ви шукаєте, але сподіваюся, що це допоможе

Редагувати : відповісти на ваш коментар

Роль - це як дозвіл у захисті весни. використання intercept-url з hasRole забезпечує дуже тонкий зернистий контроль того, яка операція дозволена, для якої ролі / дозволу.

У нашому застосуванні ми визначаємо дозвіл (тобто роль) для кожної операції (або URL-адреси відпочинку), наприклад, view_account, delete_account, add_account і т.д. Профілі - це просто логічне групування дозволів, незалежних від безпеки джерела. Коли додається новий користувач, йому призначається профіль (маючи всі допустимі дозволи). Тепер, коли будь-який користувач намагається виконати якусь дію, дозвіл / роль для цієї дії перевіряється щодо наданих користувачем повноважень.

Також за замовчуванням RoleVoter використовує префікс ROLE_, тому будь-яка влада, що починається з ROLE_, вважається роллю, ви можете змінити цю поведінку за замовчуванням, використовуючи користувацький RolePrefix у ролі виборця та використовуючи його у захисті весни.


1
Дякую за твою допомогу. Ієрархія виглядає як щось інше. Те, як я думаю про це зараз (якщо мені доведеться використовувати Spring Security), зберігає і роль, і повноваження в одному списку і використовує предикат hasRole для здійснення перевірок для обох. Думаючи про це більше - це, мабуть, залишилося навмисно хлопцями у Spring Security? Чи є можливість використовувати intercept-url, крім перевірки за допомогою hasRole, у повному списку ролей та привілеїв / повноважень - або інших додатках авторизації. Крім того, у чому полягає потреба у префіксі ROLE_? Це конвенція?
Chinmay

7

Інший спосіб зрозуміти взаємозв'язок між цими поняттями - інтерпретувати РОЛЬ як контейнер влади.

Влада має чіткі деталі дозволів, орієнтовані на конкретну дію, поєднану часом із конкретним обсягом даних або контекстом. Наприклад, Read, Write, Manage, може представляти різні рівні дозволів на певний обсяг інформації.

Крім того, повноваження застосовуються глибоко в потоці обробки запиту, в той час як ROLE фільтрується способом фільтра запиту до того, як дійти до Контролера. Найкращі практики передбачають впровадження правоохоронних органів, що пройшли через Контролер, на бізнес-рівні.

З іншого боку, ROLES є грубозернистим поданням набору дозволів. ROLE_READER матиме повноваження лише для читання чи перегляду, тоді як ROLE_EDITOR матиме читання та запис. Ролі в основному використовуються для першого екранування на околиці обробки запиту, наприклад http. ... .antMatcher (...). hasRole (ROLE_MANAGER)

Влада, яка застосовується глибоко в потоці процесу запиту, дозволяє чіткіше застосовувати дозвіл. Наприклад, користувач може мати дозвіл читання запису на перший рівень ресурсу, але лише читання на підресурсі. Наявність ROLE_READER обмежує його право редагувати ресурс першого рівня, оскільки йому потрібен дозвіл Write для редагування цього ресурсу, але перехоплювач @PreAuthorize може блокувати його попередній показник для редагування субресурсу.

Джейк


2

Як уже згадували інші, я думаю, що ролі є контейнерами для більш детальних дозволів.

Хоча я вважав, що в реалізації ієрархічної ролі не вистачає тонкого контролю над цим детальним дозволом.
Тож я створив бібліотеку для управління відносинами та введення дозволів як наданих повноважень у контексті безпеки.

У програмі може бути набір дозволів, таких як CREATE, READ, UPDATE, DELETE, які потім асоціюються з Роллю користувача.

Або більш конкретні дозволи, такі як READ_POST, READ_PUBLISHED_POST, CREATE_POST, PUBLISH_POST

Ці дозволи є відносно статичними, але відношення ролей до них може бути динамічним.

Приклад -

@Autowired 
RolePermissionsRepository repository;

public void setup(){
  String roleName = "ROLE_ADMIN";
  List<String> permissions = new ArrayList<String>();
  permissions.add("CREATE");
  permissions.add("READ");
  permissions.add("UPDATE");
  permissions.add("DELETE");
  repository.save(new RolePermissions(roleName, permissions));
}

Ви можете створити API для управління співвідношенням цих дозволів до ролі.

Я не хочу копіювати / вставляти іншу відповідь, тому ось посилання на більш повне пояснення щодо ТА.
https://stackoverflow.com/a/60251931/1308685

Для повторного використання моєї реалізації я створив репо. Будь ласка, не соромтеся робити внесок!
https://github.com/savantly-net/spring-role-permissions

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.