Grantedauthority spring что это
Перейти к содержимому

Grantedauthority spring что это

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

в Spring Security есть концепции и реализации, такие как GrantedAuthority интерфейс для получения авторитет для авторизации / управления доступом.

Я хотел бы, чтобы допустимые операции, такие как createSubUsers или deleteAccounts, который я бы позволилadmin (С ролью ROLE_ADMIN ).

я путаюсь, как учебники / демонстрации, которые я вижу в интернете. Я пытаюсь связать то, что читаю, но думаю мы относимся к ним взаимозаменяемо.

Я вижу hasRole потребление GrantedAuthority строку? Я определенно делаю это неправильно понять. Что это такое концептуально в Spring Security?

как сохранить роль пользователя, отдельно от властей для этой роли?

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

или есть какой-либо другой способ отличить два других? Или это не поддерживается, и мы должны сделать наши собственные?

3 ответов

getAuthority() метод). Эти строки позволяют идентифицировать разрешения и позволяют вашим избирателям решать, предоставляют ли они доступ к чему-либо.

вы можете предоставить пользователям различные GrantedAuthoritys (разрешения), поместив их в контекст безопасности. Обычно вы делаете это, реализуя свой собственный UserDetailsService, который возвращает UserDetails реализация, которая возвращает необходимые GrantedAuthorities.

роли (как они используются во многих примерах) — это просто «разрешения» с Соглашением об именах, которое говорит, что роль является GrantedAuthority, которая начинается с префикса ROLE_ . Больше ничего нет. Роль — это просто дарованное право — «разрешение» — «право». Вы видите много мест в spring security, где роль с ее ROLE_ префикс обрабатывается специально, например, в RoleVoter, где ROLE_ префикс используется по умолчанию. Это позволяет предоставить имена ролей без ROLE_ префикс. До Spring security 4 Эта специальная обработка «ролей» не соблюдалась очень последовательно, и власти и роли часто рассматривались одинаково (как вы, например, можете видеть в реализации hasAuthority() метод SecurityExpressionRoot — который просто называет hasRole() ). С Spring Security 4 обработка ролей более последовательна и код, который имеет дело с «ролями» (например, RoleVoter на hasRole выражение etc.) всегда добавляет ROLE_ префикс для вас. Так что hasAuthority(‘ROLE_ADMIN’) означает то же, как hasRole(‘ADMIN’) потому что ROLE_ префикс добавляется автоматически. Весны безопасности 3 до 4 руководство по миграции для получения дополнительной информации.

но все же: роль — это просто авторитет со специальным ROLE_ префикс. Так что весной безопасность 3 @PreAuthorize(«hasRole(‘ROLE_XYZ’)») это то же самое, что @PreAuthorize(«hasAuthority(‘ROLE_XYZ’)») а весной безопасность 4 @PreAuthorize(«hasRole(‘XYZ’)») это то же самое, что @PreAuthorize(«hasAuthority(‘ROLE_XYZ’)») .

относительно вашего варианта использования:

пользователи имеют роли и роли могут выполнять определенные операции.

вы можете оказаться в GrantedAuthorities для ролей, к которым принадлежит пользователь, и операций, которые может выполнять роль. The GrantedAuthorities для ролей есть префикс ROLE_ и операции имеют префикс OP_ . Примером для оперативных органов может быть OP_DELETE_ACCOUNT , OP_CREATE_USER , OP_RUN_BATCH_JOB etc. Роли могут быть ROLE_ADMIN, ROLE_USER так далее.

вы можете в конечном итоге реализовать свои сущности GrantedAuthority как в этот (псевдо-код) пример:

идентификаторами ролей и операций, которые вы создаете в своей базе данных, будет представление 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.

AFAIK GrantedAuthority и роли одинаковы в spring security. Строка getAuthority () GrantedAuthority является ролью (согласно реализации по умолчанию SimpleGrantedAuthority).

для вашего случая вы можете использовать иерархические роли

Не точный sol, который вы ищете, но надеюсь, что это поможет

редактировать: ответ на ваш комментарий

роль похожа на разрешение в spring-security. использование intercept-url с hasRole обеспечивает очень мелкозернистый контроль того, какая операция разрешена для какой роли / разрешения.

как мы обрабатываем в нашем приложении, мы определяем разрешение (т. е. роль) для каждой операции (или url rest), например, view_account, delete_account, add_account и т. д. Затем мы создаем логические профили для каждого пользователя, такие как admin, guest_user, normal_user. Профили — это просто логическая группировка разрешений, независимая от spring-security. При добавлении нового пользователя ему присваивается профиль (имеющий все допустимые разрешения). Теперь, когда пользователь пытается выполнить какое-либо действие, разрешение/роль для этого действия проверяется против пользователя grantedAuthorities.

также defaultn RoleVoter использует префикс ROLE_, поэтому любой орган, начинающийся с ROLE_, считается ролью, вы можете изменить это поведение по умолчанию, используя пользовательский RolePrefix в Role voter и используя его в spring security.

другой способ понять взаимосвязь между этими понятиями-интерпретировать роль как контейнер полномочий.

полномочия-это мелкозернистые разрешения, нацеленные на конкретное действие, иногда связанное с определенной областью данных или контекстом. Например, чтение, запись, Управление, могут представлять различные уровни разрешений для данной области информации.

кроме того, полномочия применяются глубоко в потоке обработки запроса, в то время как роль фильтруется путем фильтра запроса перед достижением контроллера. Наилучшая практика предписывает осуществлять правоприменение органов за пределами контролера на бизнес-уровне.

с другой стороны, роли представляют собой грубое представление набора разрешений. ROLE_READER будет только читать или просматривать полномочия, в то время как ROLE_EDITOR будет читать и писать. Роли главным образом использованы для первого скрининга на outskirt обработки запроса как http. . .antMatcher(. ).hasRole (ROLE_MANAGER)

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

Difference between Role and GrantedAuthority in Spring Security

There are concepts and implementations in Spring Security, such as the GrantedAuthority interface to get an authority to authorize/control an access.

I would like that to permissible operations, such as createSubUsers, or deleteAccounts, which I would allow to an admin (with role ROLE_ADMIN ).

I am getting confused as the tutorials/demos I see online. I try to connect what I read, but I think we treat the two interchangeably.

I see hasRole consuming a GrantedAuthority string? I most definitely am doing it wrong in understanding. What are these conceptually in Spring Security?

How do I store the role of a user, separate from the authorities for that role?

I’m also looking at the org.springframework.security.core.userdetails.UserDetails interface which is used in the authentication-provider referenced DAO, which consumes a User (note last GrantedAuthority):

Or is there any other way to differentiate the other two? Or is it not supported and we have to make our own?

user avatar

4 Answers 4

Think of a GrantedAuthority as being a «permission» or a «right». Those «permissions» are (normally) expressed as strings (with the getAuthority() method). Those strings let you identify the permissions and let your voters decide if they grant access to something.

You can grant different GrantedAuthoritys (permissions) to users by putting them into the security context. You normally do that by implementing your own UserDetailsService that returns a UserDetails implementation that returns the needed GrantedAuthorities.

Roles (as they are used in many examples) are just «permissions» with a naming convention that says that a role is a GrantedAuthority that starts with the prefix ROLE_ . There’s nothing more. A role is just a GrantedAuthority — a «permission» — a «right». You see a lot of places in spring security where the role with its ROLE_ prefix is handled specially as e.g. in the RoleVoter, where the ROLE_ prefix is used as a default. This allows you to provide the role names withtout the ROLE_ prefix. Prior to Spring security 4, this special handling of «roles» has not been followed very consistently and authorities and roles were often treated the same (as you e.g. can see in the implementation of the hasAuthority() method in SecurityExpressionRoot — which simply calls hasRole() ). With Spring Security 4, the treatment of roles is more consistent and code that deals with «roles» (like the RoleVoter , the hasRole expression etc.) always adds the ROLE_ prefix for you. So hasAuthority(‘ROLE_ADMIN’) means the the same as hasRole(‘ADMIN’) because the ROLE_ prefix gets added automatically. See the spring security 3 to 4 migration guide for futher information.

But still: a role is just an authority with a special ROLE_ prefix. So in Spring security 3 @PreAuthorize(«hasRole(‘ROLE_XYZ’)») is the same as @PreAuthorize(«hasAuthority(‘ROLE_XYZ’)») and in Spring security 4 @PreAuthorize(«hasRole(‘XYZ’)») is the same as @PreAuthorize(«hasAuthority(‘ROLE_XYZ’)») .

Regarding your use case:

Users have roles and roles can perform certain operations.

You could end up in GrantedAuthorities for the roles a user belongs to and the operations a role can perform. The GrantedAuthorities for the roles have the prefix ROLE_ and the operations have the prefix OP_ . An example for operation authorities could be OP_DELETE_ACCOUNT , OP_CREATE_USER , OP_RUN_BATCH_JOB etc. Roles can be ROLE_ADMIN , ROLE_USER , ROLE_OWNER etc.

You could end up having your entities implement GrantedAuthority like in this (pseudo-code) example:

The ids of the roles and operations you create in your database would be the GrantedAuthority representation, e.g. ROLE_ADMIN , OP_DELETE_ACCOUNT etc. When a user is authenticated, make sure that all GrantedAuthorities of all its roles and the corresponding operations are returned from the UserDetails.getAuthorities() method.

Example: The admin role with id ROLE_ADMIN has the operations OP_DELETE_ACCOUNT , OP_READ_ACCOUNT , OP_RUN_BATCH_JOB assigned to it. The user role with id ROLE_USER has the operation OP_READ_ACCOUNT .

If an admin logs in the resulting security context will have the GrantedAuthorities: ROLE_ADMIN , OP_DELETE_ACCOUNT , OP_READ_ACCOUNT , OP_RUN_BATCH_JOB

If a user logs it, it will have: ROLE_USER , OP_READ_ACCOUNT

The UserDetailsService would take care to collect all roles and all operations of those roles and make them available by the method getAuthorities() in the returned UserDetails instance.

Как устроена Аутентификация в Spring Security

Аутентификация — это проверка, что пользователь есть тот, за кого себя выдает. Чтобы выполнить проверку, надо:

  • Извлечь имя и пароль из HTTP-запроса. За это отвечает UsernamePasswordAuthenticationFilter (конкретно в нашем приложении с Form-Based аутентификацией).
  • Сравнить их с реальными именем и паролем, хранящимся где-то (в базе, на LDAP-сервере, во временной памяти приложения и т.д. где угодно). Это делает AuthenticationManager в методе authenticate().
    Вызывается authenticate() из фильтра UsernamePasswordAuthenticationFilter сразу после извлечения имени/пароля из HTTP-запроса.

Метод authenticate(Authentication authentication) интерфейса AuthenticationManager — проверка пароля

Допустим, нам приходит HTTP-запрос. Прежде чем попасть в контроллер, запрос проходит через цепочку фильтров. В UsernamePasswordAuthenticationFilter имя и пароль вытаскиваются из запроса. Дальше надо их сравнить с реальными. Тут то вступает в дело AuthenticationManager:

Его единственный метод authenticate() выполняет аутентификацию, то есть решает, действительно ли пользователь тот, за кого себя выдает. Делегируется проверка конкретным провайдерам (в зависимости от того, как хранится реальный пользователь, проверка разнится).

Authentication до аутентификации

Как видно в коде выше, метод authenticate() получает на вход объект Authentication с именем и паролем, полученными от клиента и требующими проверку. Имя хранится в principal, а пароль в credenticals (до проверки, после проверки будет иначе):

До проверки в выделенных полях хранятся имя и пароль

До проверки в выделенных полях хранятся имя и пароль

Содержимое объекта Authentication можно проверить, если запустить предыдущий пример и поставить break-point в методе authenticate() класса ProviderManager. А потом по адресу /login отправить POST-запрос с формы ввода имени/пароля:

До аутентификации

До аутентификации

isAuthenticated() до аутентификации равно false.

Если аутентификация не прошла (имя и пароль неверны), то выбрасывается исключение BadCredentials.

В случае же успеха возвращается тоже объект Authentication, но заполненный по-другому.

Authentication после аутентификации

После аутентификации в поле Principal объекта Authentication будет реальный пользователь в виде UserDetails:

После аутентификации

После аутентификации

При этом поле Credentials обнуляется, а isAuthenticated() меняется с false на true.

То есть имя и пароль перемещаются объект Principal:

Проверить содержимое объекта Authentication после аутентификации можно, внедрив его в контроллер и поставив в нем break-point (смотреть переменные нужно, когда заходишь под уже залогиненным пользователем; поскольку в нашем примере мы настраивали, что путь /user доступен только для залогиненного пользователя, то есть после того, как аутентификация уже успешно прошла):

Вывод в консоль:

break-point

break-point

Как же AuthenticationManager в authenticate() решает, правильный пароль, или нет? Очевидно, для этого надо сравнить переданный пароль с реальным. А для этого по переданному имени надо извлечь реального пользователя. И вот тут дальнейшее зависит от того, где этот пользователь хранится.

Типы аутентификации в Spring Security

Есть несколько стандартных типов хранения и извлечения пользователя, и за каждый из них отвечает свой AuthenticationProvider. AuthenticationManager делегирует провайдеру извлечь данные их хранилища. В Spring Security реализованы несколько стандартных провайдеров, все они задаются в методе configure():

  • In-Memory — простейший, задан в вышеприведенном фрагменте кода из примера
  • Jdbc — рассмотрим в следующей статье
  • LDAP

А можно написать свой, так чаще всего и делают (тоже сделано в следующей статье).

Все упирается в получение реального пользователя по его имени — в метод loadUserByName интерфейса UserDetailsService:

где UserDetails содержит информацию о реальном пользователе (точнее, нам надо составить эту информацию из того, что есть в базе, например).

И составляем мы ее как раз в методе loadUserByUsername(), если реализовываем его вручную. Важно заполнить password, username и authorities (права) объекта UserDetails .

Но вернемся к методу authenticate(), в котором происходит аутентификация.

SecurityContext — хранилище объекта Authentication

Допустим, аутентификация прошла успешно — это значит, имя и пароль верные.

Тогда объект Authentication сохраняется в SecurityContext, а тот, в свою очередь, — в SecurityContextHolder:

SecurityContextHolder

SecurityContextHolder

Текущего пользователя из него можно получить так:

Таким образом, SecurityContext используется для хранения объекта Authentication.

Восстановление Authentication из сессии

Аутентификация в нашем примере происходит только раз. Коль скоро она прошла успешно, authentication восстанавливается из контекста, а в итоге из сессии при последующих запросах. Происходит это в SecurityContextPersistenceFilter.

Сессии в нашем примере включены — они включены по умолчанию, если их специально не отключить. То есть после аутентификации в HTTP-ответе клиенту отправляется уникальный JSESSIONID, который он отправляет во всех последующих запросах. По JSESSIONID восстанавливается сессия, из нее берется SecurityContext, а из него Authentication.

Итоги

В тексте выше приводились примеры кода и ставились break-point приложения из статьи.

В следующем примере напишем пользовательскую аутентификацию с помощью UserDetailsService.

Как устроена Аутентификация в Spring Security: 9 комментариев

Самое интересное для меня за кадром осталось(( Не могли бы описать не просто текстом, а код-снипетами (ну или псевдокодом) вот эту часть таинства из последнего буквально предложения: «По JSESSIONID восстанавливается сессия, из нее берется SecurityContext». Хотелось бы понять как оно работает. В принципе в поисках этого кусочка я и забрел сюда, а и тут нет…..
Буду очень благодарен.

1) Если больше интересует 1-часть, а именно как «По JSESSIONID восстанавливается сессия» — то к Spring это особого отношения не имеет. Запущенный контейнер сервлетов Tomcat (независимо от Spring) хранит в куче (по умолчанию в куче, но есть варианты) объекты HttpSession пользователей. Это можно представить как ключ-значение, немного подробнее тут (первая часть статьи).

2) «из нее берется SecurityContext»
За это отвечает в Spring фильтр SecurityContextPersistenceFilter

Есть класс HttpSessionSecurityContextRepository implements SecurityContextRepository, так вот в методе SecurityContext loadContext() (а из него в readSecurityContextFromSession()) контекст извлекается в сниппете:
Object contextFromSession = httpSession.getAttribute(springSecurityContextKey)

где springSecurityContextKey — строка «SPRING_SECURITY_CONTEXT» — атрибут обычной томкатовской сессии HttpSession. В понятии «атрибут сессии» тоже нет ничего Spring-специфичного. Вот просто есть такой «SPRING_SECURITY_CONTEXT» атрибут, который Spring использует для своих целей — для хранения контекста.

Да, а в фильтре SecurityContextPersistenceFilter как раз и вызываются методы сохранения и извлечения контекста из HttpSessionSecurityContextRepository

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *