Java >> Java tutorial >  >> Tag >> Spring

Brugerstyring med Okta SDK og Spring Boot

I dette indlæg vil jeg vise, hvordan vi kan bygge brugeradministration og godkendelse med Okta SDK og Spring Boot.

Introduktion

Som en del af enhver applikation skal udviklere være forsigtige med, hvordan de opbygger godkendelse. På trods af at vi har brugt formularbaseret godkendelse i lang tid, er det ikke den mest sikre. I dette indlæg planlægger jeg at vise formularbaseret godkendelse, hvor brugere ikke nødvendigvis bliver godkendt ved at validere deres krypterede adgangskode mod adgangskoden, der er gemt i en database. Hvis du vil lære mere om Spring Security med forskellige autentificeringsflows, har jeg for nylig udgivet en bog Simplifying Spring Security. Du kan købe bogen her.

Okta er en identitetsudbyder. Det er et program, der giver brugeradministration og godkendelse med forskellige protokoller.

Okta SDK API'er

Okta tilbyder to biblioteker okta-sdk-java og okta-auth-java til brugerstyrings-API'er og godkendelse.

Er disse biblioteker rigtige for dig? Dette afhænger af din use case. Okta tilbyder også okta-spring-boot-starter bibliotek til at bruge okta til forskellige OAuth-flows i din Spring Boot-applikation. Vi vil ikke bruge dette bibliotek i denne demo.

Du kan finde flere detaljer om disse biblioteker her og her.

Inkluder disse biblioteker i dit projekt som følger:


	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'

Brugeradministration med Okta SDK i Spring Boot Application

I denne demo har jeg en prøveanvendelse af To-Do List. Når en bruger starter programmet, vil brugeren se en login-skærm. Den har mulighed for tilmelding. Hvis brugeren ikke findes i applikationen, skal brugeren oprette en konto.

På tilmeldingssiden, når en bruger indtaster knappen "Send", gemmer vi brugeren i vores database og kalder derefter Okta SDK API for at oprette brugeren på Okta-siden.

For at opnå dette har vi brug for Okta Client.


    @Bean
    public Client client()
    {

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


        return clientConfig;

    }

Som du kan se ovenfor, opretter vi en klient, som vi vil bruge til at kalde Okta API. `Hemmeligheden` ​​er API-tokenet, du vil kunne finde i Okta admin UI. Hvis du ikke finder det, har du enten ikke administratorrettigheder, eller også har du ikke oprettet tokenet endnu. Der er en anden måde at oprette denne klient med et adgangstoken.


    @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;

    }

Fordelen ved denne klientkonfiguration er, at du ikke behøver at kende API-adgangstoken, der er oprettet baseret på administratorrettigheder.

Nu på min controller-side vil jeg bruge denne klient til at oprette bruger i Okta som nedenfor:


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

Det dækker brugeradministrationsdelen. Du kan på samme måde ringe til GET eller DELETE API til at administrere brugere.

Brugergodkendelse

Nu kommer den kritiske del af autentificering. I mange virksomhedsapplikationer, når du bruger tredjeparts identitet, kommer problemet altid med synkronisering af brugerdata. Begge applikationer skal gemme brugerdata.

Til godkendelse skal vi bruge authenticationClient bønne. Denne klient giver os mulighed for at kalde Okta API til godkendelse.


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

        return authenticationClient;
    }

I vores sikkerhedskonfiguration vil jeg tilsidesætte det formularbaserede login med en tilpasset loginside.



    @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();

    }

Som du ser i ovenstående kode, bruger jeg customAuthenticationProvider , vil denne udbyder bruge authenticationClient at godkende med Okta. Denne AuthenticationProvider vil se ud som nedenfor:


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

Vi bruger authenticationClient at kalde godkendelsesmetoden. AuthenticationStateHandler håndterer grundlæggende statusgodkendelsen. Implementeringen af ​​dette håndtag er som nedenfor:


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 : "/";

        }
    }
}

Det er alt. Dette dækker brugergodkendelse. Husk, at dette stadig er formularbaseret godkendelse, hvor du indtaster brugeroplysninger på din brugerdefinerede login-side og bag skærmen kalder Okta API for at godkende.

I min bog, Simplifying Spring Security, har jeg også tilføjet demoen til login med Okta OAuth.

Konklusion

I dette indlæg viste jeg, hvordan man bruger Okta SDK til brugeradministration og godkendelse med Spring Boot-applikationen. Hvis du har spørgsmål, er du velkommen til at sende mig en e-mail ved at abonnere på min blog her.


Java tag