Как определить предоставленные пользователем полномочия на основе ролей пользователей в Auth0 с помощью Spring Boot

Используя Auth0 в качестве поставщика услуг OAuth, мы знаем, что роли могут влиять на пользователей (пока остаемся только на уровне Auth0). Однако эти роли не считаются напрямую предоставленными полномочиями при входе пользователя в систему. Я хотел иметь возможность получать роли пользователей с помощью API управления Auth0, чтобы получать роли пользователей и определять полномочия на основе ролей, которые будут предоставлены моему аутентифицированному пользователю. . Является ли это хорошей практикой в ​​целом, и если да, то как мне действовать? Я пробовал некоторые конкретные реализации, но все еще сталкиваюсь с проблемой.

Я реализовал Customer OAuthUser, CustomOAuthUserService и добавил свой сервис в файл конфигурации безопасности Spring.

Вот мой пользовательский OAuthUser:

package com.interco.reconciliation.model;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
import org.springframework.security.oauth2.core.user.OAuth2User;

import java.util.Collection;
import java.util.List;
import java.util.Map;

public class CustomOAuth2User extends DefaultOAuth2User {

    private final OAuth2User delegate;
    private final Collection<GrantedAuthority> authorities;


    public CustomOAuth2User(OAuth2User delegate, Collection<GrantedAuthority> authorities) {
        super(authorities, delegate.getAttributes(), "name");
        this.delegate = delegate;
        this.authorities = authorities;
    }

    @Override
    public Map<String, Object> getAttributes() {
        return this.delegate.getAttributes();
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    @Override
    public String getName() {
        return this.delegate.getAttribute("name");
    }

}

Вот моя пользовательская служба OAuth:

package com.interco.reconciliation.service;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import com.interco.reconciliation.model.CustomOAuth2User;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.exceptions.UnirestException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;


@Service
public class CustomOAuth2UserService extends DefaultOAuth2UserService {

    @Autowired
    private Auth0ApiManagementService auth0ApiManagementService;

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) {
        OAuth2User oAuth2User = super.loadUser(userRequest);
        List<GrantedAuthority> authorities = new ArrayList<>(oAuth2User.getAuthorities());
        String userId = oAuth2User.getAttribute("sub");

        try {
            HttpResponse<JsonNode> roles = this.auth0ApiManagementService.getUserRoles(userId);
            JsonNode rolesBody = roles.getBody();
            for(int i = 0; i < rolesBody.getArray().length(); i++) {
                JSONObject role = rolesBody.getArray().getJSONObject(i);
                String roleName = role.getString("name");
                authorities.add(new SimpleGrantedAuthority("ROLE_" + roleName));
            }
        } catch (UnirestException | UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        System.out.println("User retrieved and authorities assigned");
        return new CustomOAuth2User(oAuth2User, authorities);
    }

}

Вот мой файл конфигурации безопасности:

package com.interco.reconciliation.config;

import static org.springframework.security.config.Customizer.withDefaults;

import com.interco.reconciliation.service.Auth0ApiManagementService;
import com.interco.reconciliation.service.CustomOAuth2UserService;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.exceptions.UnirestException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;

import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import java.io.IOException;


@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {

    @Value("${okta.oauth2.issuer}")
    private String issuer;
    @Value("${okta.oauth2.client-id}")
    private String clientId;
    @Autowired
    private CustomOAuth2UserService customOAuth2UserService;


    @Bean
    public SecurityFilterChain configure(HttpSecurity http) throws Exception {
        http
                .csrf(AbstractHttpConfigurer::disable) // remove later or configure appropriately in production
                .cors(withDefaults()) // remove later or configure appropriately in production
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers("/").permitAll()
                        .anyRequest().authenticated()
                )
                .oauth2Login(oauth2Login ->
                        oauth2Login
                                .userInfoEndpoint(userInfoEndpoint ->
                                        userInfoEndpoint.userService(customOAuth2UserService)))
                .logout(logout -> logout
                        .addLogoutHandler(logoutHandler()));
        return http.build();
    }
    

    private LogoutHandler logoutHandler() {
        return (request, response, authentication) -> {
            try {
                String baseUrl = ServletUriComponentsBuilder.fromCurrentContextPath().build().toUriString();
                response.sendRedirect(issuer + "v2/logout?client_id = " + clientId + "&returnTo = " + baseUrl);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        };
    }

}

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
57
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы настраиваете клиент Spring OAuth2 (с помощью oauth2Login). Вам нужно:

P.S. № 1

Если вы настраивали oauth2ResourceServer (REST API, авторизованный с использованием токенов на предъявителя) с декодером JWT, вам необходимо:

P.S. № 2

У меня есть дополнительный стартер Spring Boot, который, среди прочего, может:

  • Создайте экземпляр и настройте GrantedAuthoritiesMapper или Converter<Jwt, AbstractAuthenticationToken> для себя.
  • У клиентов с oauth2Login:
    • Обработайте параметр audience, необходимый для запроса авторизации.
    • Помогите настроить защиту CSRF, которую следует включить, поскольку авторизация запросов к клиентам Spring OAuth2 с помощью oauth2Login основана на сеансах.
  • На серверах ресурсов при необходимости настройте CORS.

Другие вопросы по теме

Похожие вопросы

Как я могу пройти аутентификацию, используя тип гранта обмена токенами для олицетворения с помощью Spring Boot и Keycloak?
Какой алгоритм шифрования использует PasswordEncoder Spring Security?
Spring безопасность: как скрыть или обойти страницу «вход с помощью oauth2» с помощью одного клиента oauth при использовании oauth2Login
Как обойти страницу входа в систему keycloak и предоставить предложенному клиентом идентификатору Spring Security
Spring Security. Эта страница не работает. Localhost перенаправлял вас слишком много раз. при попытке доступа к localhost:8080 с помощью Spring Security
Почему мой пользователь анонимен после входа в систему по OAuth2 с помощью Spring Boot?
Ошибка происхождения Cors приложения микросервиса Spring Boot
Spring безопасность oauth2Login на основе средства сопоставления запросов
Пытается ли Spring Security авторизовать клиента для общедоступной конечной точки?
Используя Spring Security 6.2.4, но я не могу найти проверку hasScope в HttpSecurity