[JAVA] Multi-projet avec Keycloak

introduction

Afin d'utiliser des micro-services dans plusieurs projets, j'ai essayé de réécrire le domaine de Keycloak pour chaque demande, mais je me suis rendu compte qu'il n'était pas réaliste de gérer les utilisateurs pour chaque domaine, et l'authentification / autorisation qui a été faite avec Keycloak J'ai décidé de séparer la partie autorisation.

Ce que j'ai essayé

Depuis que le microservice backend a été implémenté dans Spring Boot, j'ai ajouté un filtre pour ajouter de nouvelles informations d'autorisation à la chaîne de filtres de sécurité de Spring.

La théorie est que si vous enregistrez un membre avec l'adresse e-mail comme identifiant unique de l'utilisateur pour chaque projet, vous pouvez identifier l'utilisateur avec l'adresse e-mail du jeton JWT de Keycloak.

Dans les cas d'utilisation où le même utilisateur participe à plusieurs projets, il est plus flexible de le séparer de Keycloak car vous souhaitez gérer les informations d'autorisation pour chaque projet.

De plus, la place pour ajouter un nouveau filtre semble être bonne après SessionManagementFilter.class.

Code source

public class CustomKeycloakFilter implements Filter {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final ProjectMemberService service;

    @Override
    public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
        logger.debug("######## CUSTOM KEYCLOAK FILTER INITIALIZED ########");
    }

    public CustomKeycloakFilter(ProjectMemberService service) {
        this.service = service;
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        
        logger.debug("######## CUSTOM KEYCLOAK FILTER ########");

        // extract project id from the request header
        String projectId = request.getHeader("project-id");
        logger.debug("++++++++ PROJECT ID: {} ++++++++", projectId);
        
        // extract Kycloak authentication token
        Principal principal = request.getUserPrincipal();
        if (principal != null && principal instanceof KeycloakAuthenticationToken) {
            
            logger.debug("++++++++ AUTHENTICATED BY KEYCLOAK ++++++++", principal.getClass().getName());

            KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) principal;
            KeycloakSecurityContext context = (KeycloakSecurityContext)token.getAccount().getKeycloakSecurityContext();
            AccessToken accessToken = context.getToken();
            
            // extract email from the access token as a unique user identifier.
            String email = accessToken.getEmail();

            logger.debug("++++++++ email: {} ++++++++", email);

            if (projectId != null && email != null) {
                
                // retrieve project user permissions from the project database by project id and user email 
                Collection<? extends GrantedAuthority> authorities = service.getAuthz(UUID.fromString(projectId), email);

                List<String> authorityStringList = new ArrayList<>();
                authorities.forEach(o -> authorityStringList.add(o.getAuthority()));
                logger.debug("++++++++ AUTHOTITIES: {} ++++++++", authorityStringList);

                // generates a new authentication token with reloaded user permissions
                KeycloakAuthenticationToken newAuthenticationToken = new KeycloakAuthenticationToken(token.getAccount(), false, authorities);
                
                logger.debug("++++++++ NEW AUTHENTICATION TOKEN: {} ++++++++", newAuthenticationToken.toString());
                
                SecurityContext sc = SecurityContextHolder.getContext();
                
                // replaces authentication token with the new one
                sc.setAuthentication(newAuthenticationToken);
            }
        }
        chain.doFilter(request, response);
    }
}

Résumé

En séparant la partie autorisation de l'authentification / autorisation de Keycloak, il était possible de prendre en charge le multi-projet (~~ multi-tenant ~~). Étant donné que les informations d'autorisation peuvent être gérées pour chaque projet, il semble que le projet puisse être exploité avec un degré élevé de liberté.

Matériel de référence

Recommended Posts

Multi-projet avec Keycloak
Multi-locataire avec Keycloak
Configuration de Keycloak
Configurer un multi-projet avec des sous-répertoires dans Gradle
Je voulais classer la botte à ressort dans un multi-projet