[JAVA] Multiprojekt mit Keycloak

Einführung

Um Mikrodienste in mehreren Projekten zu verwenden, habe ich versucht, den Bereich von Keycloak für jede Anforderung neu zu schreiben, aber festgestellt, dass es nicht realistisch ist, Benutzer für jeden Bereich und die mit Keycloak durchgeführte Authentifizierung / Autorisierung zu verwalten Ich habe beschlossen, den Autorisierungsteil zu trennen.

Was ich versucht habe

Da der Backend-Mikroservice in Spring Boot implementiert wurde, habe ich einen Filter hinzugefügt, um der Sicherheitsfilterkette von Spring neue Berechtigungsinformationen hinzuzufügen.

Die Theorie besagt, dass Sie den Benutzer mit der E-Mail-Adresse des JWT-Tokens von Keycloak identifizieren können, wenn Sie ein Mitglied mit der E-Mail-Adresse als eindeutige Kennung des Benutzers für jedes Projekt registrieren.

In Anwendungsfällen, in denen derselbe Benutzer an mehreren Projekten teilnimmt, ist es flexibler, ihn von Keycloak zu trennen, da Sie Berechtigungsinformationen für jedes Projekt verwalten möchten.

Der Ort zum Hinzufügen eines neuen Filters scheint nach SessionManagementFilter.class gut zu sein.

Quellcode

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);
    }
}

Zusammenfassung

Durch Trennen des Autorisierungsteils von Keycloaks Authentifizierung / Autorisierung war es möglich, Multi-Project (~~ Multi-Tenant ~~) zu unterstützen. Da die Autorisierungsinformationen für jedes Projekt verwaltet werden können, scheint es, dass das Projekt mit einem hohen Freiheitsgrad betrieben werden kann.

Referenzmaterial

Recommended Posts

Multiprojekt mit Keycloak
Multi-Tenant mit Keycloak
Keycloak-Setup
Konfigurieren Sie ein Multiprojekt mit Unterverzeichnissen in Gradle
Ich wollte Spring Boot in einem Multiprojekt gradle