Java >> Java Tutorial >  >> Tag >> Spring

Benutzerverwaltung mit Okta SDK und Spring Boot

In diesem Beitrag werde ich zeigen, wie wir Benutzerverwaltung und -authentifizierung mit Okta SDK und Spring Boot aufbauen können.

Einführung

Als Teil jeder Anwendung müssen Entwickler darauf achten, wie sie die Authentifizierung erstellen. Obwohl wir seit langem die formularbasierte Authentifizierung verwenden, ist sie nicht die sicherste. In diesem Beitrag möchte ich die formularbasierte Authentifizierung zeigen, bei der Benutzer nicht unbedingt authentifiziert werden, indem ihr verschlüsseltes Passwort mit dem in einer Datenbank gespeicherten Passwort validiert wird. Wenn Sie mehr über Spring Security mit verschiedenen Authentifizierungsabläufen erfahren möchten, habe ich kürzlich ein Buch Simplifying Spring Security veröffentlicht. Sie können das Buch hier kaufen.

Okta ist ein Identitätsanbieter. Es ist eine Anwendung, die Benutzerverwaltung und -authentifizierung mit verschiedenen Protokollen bereitstellt.

Okta SDK-APIs

Okta bietet zwei Bibliotheken okta-sdk-java und okta-auth-java für Benutzerverwaltungs-APIs und Authentifizierung.

Sind diese Bibliotheken das Richtige für Sie? Dies hängt von Ihrem Anwendungsfall ab. Okta bietet auch okta-spring-boot-starter an Bibliothek, um Okta für verschiedene OAuth-Flows in Ihrer Spring Boot-Anwendung zu verwenden. Wir werden diese Bibliothek in dieser Demo nicht verwenden.

Weitere Einzelheiten zu diesen Bibliotheken finden Sie hier und hier.

Binden Sie diese Bibliotheken wie folgt in Ihr Projekt ein:


	implementation 'com.okta.authn.sdk:okta-authn-sdk-api:2.0.1'
	runtimeOnly 'com.okta.authn.sdk:okta-authn-sdk-impl:2.0.1'
	runtimeOnly 'com.okta.sdk:okta-sdk-httpclient:3.0.1'

Benutzerverwaltung mit Okta SDK in der Spring Boot-Anwendung

In dieser Demo habe ich eine Beispielanwendung der Aufgabenliste. Wenn ein Benutzer die Anwendung startet, wird dem Benutzer ein Anmeldebildschirm angezeigt. Es hat eine Anmeldeoption. Wenn der Benutzer in der Anwendung nicht vorhanden ist, muss der Benutzer ein Konto erstellen.

Wenn ein Benutzer auf der Anmeldeseite auf die Schaltfläche „Senden“ klickt, speichern wir den Benutzer in unserer Datenbank und rufen dann die Okta SDK-API auf, um den Benutzer auf Okta-Seite zu erstellen.

Um dies zu erreichen, benötigen wir Okta Client.


    @Bean
    public Client client()
    {

        Client clientConfig =
                Clients.builder().setOrgUrl("https://oktadomainurl").setClientCredentials(new TokenClientCredentials(secret))
                        .build();


        return clientConfig;

    }

Wie Sie oben sehen, erstellen wir einen Client, mit dem wir die Okta-API aufrufen. Das „Geheimnis“ ist das API-Token, das Sie in der Okta-Admin-Benutzeroberfläche finden können. Wenn Sie es nicht finden, haben Sie entweder keine Administratorrechte oder Sie haben das Token noch nicht erstellt. Es gibt eine andere Möglichkeit, diesen Client mit einem Zugriffstoken zu erstellen.


    @Bean
    public Client client()
    {

        Client clientConfig =
                Clients.builder().setOrgUrl("https://oktadomainurl")
                      .setAuthorizationMode(AuthorizationMode.PRIVATE_KEY).setClientId("{clientId}")
                      .setScopes(new HashSet<>(Arrays.asList("okta.users.read", "okta.apps.read")))
                      .setPrivateKey("/path/to/yourPrivateKey.pem")


        return clientConfig;

    }

Der Vorteil dieser Client-Konfiguration besteht darin, dass Sie kein API-Zugriffstoken kennen müssen, das basierend auf Administratorrechten erstellt wurde.

Jetzt werde ich auf meiner Controller-Seite diesen Client verwenden, um Benutzer in Okta wie folgt zu erstellen:


        UserDto userDto = new UserDto();
        userDto.setEmail(email);
        userDto.setFirstName(firstname);
        userDto.setLastName(lastname);
        userDto.setPassword(encodedPassword);
        userDto.setRole("ADMIN");
        userDto.setEnabled(true);

        UserDto returnedUser = usersManager.createUser(userDto);

        LOGGER.info("Create the user in Okta");

        User oktaUser = UserBuilder.instance().setEmail(returnedUser.getEmail())
                .setFirstName(returnedUser.getFirstName())
                .setLastName(returnedUser.getLastName())
                .buildAndCreate(client);

Das deckt den Teil der Benutzerverwaltung ab. Sie können auf ähnliche Weise GET aufrufen oder DELETE API zum Verwalten von Benutzern.

Benutzerauthentifizierung

Jetzt kommt der entscheidende Teil der Authentifizierung. In vielen Unternehmensanwendungen kommt es bei der Verwendung von Identitätsanbietern von Drittanbietern immer zu Problemen mit der Synchronisierung der Benutzerdaten. Beide Anwendungen müssen Benutzerdaten speichern.

Zur Authentifizierung benötigen wir authenticationClient Bohne. Dieser Client ermöglicht es uns, die Okta-API zur Authentifizierung aufzurufen.


    @Bean
    public AuthenticationClient authenticationClient()
    {
        AuthenticationClient authenticationClient =
                AuthenticationClients.builder()
                        .setOrgUrl("https://oktadomainurl")
                        .build();

        return authenticationClient;
    }

In unserer Sicherheitskonfiguration überschreibe ich die formularbasierte Anmeldung mit einer benutzerdefinierten Anmeldeseite.



    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    @Bean(BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception
    {
        return super.authenticationManagerBean();
    }


    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception
    {

        httpSecurity.authorizeRequests()
                .antMatchers("/js/**","/css/**","/img/**").permitAll()
                .antMatchers("/signup","/forgotpassword").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .permitAll();

    }

Wie Sie im obigen Code sehen, verwende ich customAuthenticationProvider , verwendet dieser Anbieter authenticationClient sich bei Okta zu authentifizieren. Dieser AuthenticationProvider sieht wie folgt aus:


package com.betterjavacode.sss.todolist.clients;

import com.betterjavacode.sss.todolist.security.AuthenticationStateHandler;
import com.okta.authn.sdk.client.AuthenticationClient;
import com.okta.authn.sdk.resource.AuthenticationResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider
{

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomAuthenticationProvider.class);

    @Autowired
    private AuthenticationClient authenticationClient;

    @Autowired
    private AuthenticationStateHandler authenticationStateHandler;

    @Override
    public Authentication authenticate (Authentication authentication) throws AuthenticationException
    {
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();
        String relayState = "/index";
        AuthenticationResponse authnResponse = null;
        try
        {
            LOGGER.info("Going to connect to Okta");
            authnResponse = authenticationClient.authenticate(username, password.toCharArray(),
                    relayState,
                    authenticationStateHandler);
        }
        catch(com.okta.authn.sdk.AuthenticationException e)
        {
            LOGGER.error("Unable to authentcate the user", e);
        }

        if(authnResponse != null)
        {
            final List grantedAuths = new ArrayList<>();
            grantedAuths.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
            final UserDetails principal = new User(username, password, grantedAuths);
            final Authentication authen = new UsernamePasswordAuthenticationToken(principal,
                    password, grantedAuths);
            return authen;
        }
        else
        {
            LOGGER.info("Unable to authenticate");
            return null;
        }

    }

    @Override
    public boolean supports (Class<?> authentication)
    {
        return true;
    }
}

Wir verwenden authenticationClient zum Aufrufen der Authentifizierungsmethode. AuthenticationStateHandler behandelt im Wesentlichen die Statusauthentifizierung. Die Implementierung dieses Handles ist wie folgt:


package com.betterjavacode.sss.todolist.security;

import com.okta.authn.sdk.AuthenticationStateHandlerAdapter;
import com.okta.authn.sdk.resource.AuthenticationResponse;
import com.okta.commons.lang.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class AuthenticationStateHandler extends AuthenticationStateHandlerAdapter
{
    private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticationStateHandler.class);

    @Override
    public void handleUnknown (AuthenticationResponse unknownResponse)
    {
        // TO DO
    }

    @Override
    public void handleSuccess (AuthenticationResponse successResponse)
    {
        if (Strings.hasLength(successResponse.getSessionToken()))
        {
            LOGGER.info("Login successful");
            String relayState = successResponse.getRelayState();
            String dest = relayState != null ? relayState : "/";

        }
    }
}

Das ist alles. Dies umfasst die Benutzerauthentifizierung. Denken Sie daran, dass dies immer noch eine formularbasierte Authentifizierung ist, bei der Sie Benutzeranmeldeinformationen auf Ihrer benutzerdefinierten Anmeldeseite und hinter dem Bildschirm eingeben, der die Okta-API zur Authentifizierung aufruft.

In meinem Buch „Simplifying Spring Security“ habe ich auch die Demo für die Anmeldung mit Okta OAuth hinzugefügt.

Schlussfolgerung

In diesem Beitrag habe ich gezeigt, wie Okta SDK für die Benutzerverwaltung und Authentifizierung mit der Spring Boot-Anwendung verwendet wird. Wenn Sie Fragen haben, können Sie mir gerne eine E-Mail senden, indem Sie hier meinen Blog abonnieren.


Java-Tag