[JAVA] Oauth2 authentication with Spring Cloud Gateway

The source is as follows.

https://github.com/ko-aoki/spring-cloud-sample

Spring Cloud Gateway I think it's used as a microservice I wondered if it could just be used like a firewall.

Constitution

The following two services are used. [cloud-gateway] [api]

Via [cloud-gateway] Access the REST server [api]. [cloud-gateway] requires oauth2 authentication.

OAuth2 authorization server

Launch Keycloak with Docker

Start the keycloak server with Docker. Below, postgresql is selected from Docker Compose.

https://github.com/keycloak/keycloak-containers/tree/master/docker-compose-examples

The basic operation of keycloak console is as follows. https://www.keycloak.org/getting-started/getting-started-docker

To persist keycloak settings, such as users Connect to your local postgresql (also Docker). I referred to the following.

https://crudzoo.com/blog/docker-postgres

docker-compose.yml is as follows including the above contents.


version: '3'

volumes:
  postgres_data:
      driver: local

services:
  postgres:
      image: postgres
      volumes:
        - postgres_data:/var/lib/postgresql/data
        - ./docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
      environment:
        POSTGRES_DB: keycloak
        POSTGRES_USER: keycloak
        POSTGRES_PASSWORD: password
  keycloak:
      image: quay.io/keycloak/keycloak:latest
      environment:
        DB_VENDOR: POSTGRES
        DB_ADDR: postgres
        DB_DATABASE: keycloak
        DB_USER: keycloak
        DB_SCHEMA: public
        DB_PASSWORD: password
        KEYCLOAK_USER: admin
        KEYCLOAK_PASSWORD: Pa55w0rd
        # Uncomment the line below if you want to specify JDBC parameters. The parameter below is just an example, and it shouldn't be used in production without knowledge. It is highly recommended that you read the PostgreSQL JDBC driver documentation in order to use it.
        #JDBC_PARAMS: "ssl=true"
      ports:
        - 8080:8080
      depends_on:
        - postgres

Creating Realm, Client, User

Open the keycloak management console below. Akapas is in docker-compose.yml.

http://localhost:8080/auth/admin

When you log in, you will see this screen.

スクリーンショット 2020-11-05 21.54.37.png

Set as follows.

Realm:myrealm

Client ID:spring-client

Access type:confidential

Valid Redirect URIs: http://localhost:8082/*

username:myuser

Credentials

myuser/mypwd

Spring Cloud Gateway

reference

I set pom.xml and config by referring to the following site.

https://piotrminkowski.com/2020/10/09/spring-cloud-gateway-oauth2-with-keycloak/

Since spring-cloud-gateway is Webflux, the following.

https://spring.pleiades.io/spring-security/site/docs/5.2.6.RELEASE/reference/html/webflux-oauth2.html

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>cloud-gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>cloud-gateway</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>11</java.version>
        <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

With WebFlux, Spring Security Requires @EnableWebFluxSecurity.

SecurityConfig.java

package com.example.cloudgateway.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.stereotype.Component;

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

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http.authorizeExchange(exchanges -> exchanges.anyExchange().authenticated())
                .oauth2Login(withDefaults());
        http.csrf().disable();
        return http.build();
    }

}

in application.yml Set to authenticate with oauth2 and route to the api server. The settings around keycloak can be found below in the keycloak management console.

http://localhost:8080/auth/realms/myrealm/.well-known/openid-configuration

application.yml

server:
  port: 8082
  servlet:
    context-path: gw

spring:
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://localhost:8081
          predicates:
            - Path=/gw/api/{segment}
          filters:
            - SetPath=/api/{segment}
  security:
    oauth2:
      client:
        provider:
          keycloak:
            token-uri: http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token
            authorization-uri: http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/auth
            userinfo-uri: http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/userinfo
            user-name-attribute: preferred_username
        registration:
          keycloak-dev:
            provider: keycloak
            client-id: spring-client
            client-secret: d7360530-4071-4a80-96fa-d711144fb3f3
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/login/oauth2/code/keycloak"

logging.level:
  org.springframework.cloud.gateway: DEBUG
  org.springframework.security: DEBUG
  org.springframework.web.reactive.function.client: TRACE

On the REST side, create a controller normally Start with 8081.

package com.example.api;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class ApiApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApiApplication.class, args);
    }

    @GetMapping("/test")
    String home() {
        return "Hello Api";
    }
}

If you access below, the keycloak login screen will be displayed.

http://localhost:8082/gw/api/test

スクリーンショット 2020-11-05 21.28.49.png

Log in with myuser / mypwd and "Hello Api" is displayed.

Recommended Posts

Oauth2 authentication with Spring Cloud Gateway
Configure microservices with Spring Cloud (4): API Gateway
Implemented authentication function with Spring Security ②
Implemented authentication function with Spring Security ③
Implemented authentication function with Spring Security ①
Google Cloud Platform with Spring Boot 2.0.0
Let's thoroughly explain Spring Cloud Gateway
Authentication / authorization with Spring Security & Thymeleaf
DB authentication with Spring Security & hashing with BCrypt
Achieve BASIC authentication with Spring Boot + Spring Security
Send a request to the backend after authenticating with Spring Cloud Gateway
Receive emails with OAuth 2.0 authentication in Exchange Online
Add your own authentication items with Spring Security
[Introduction to Spring Boot] Authentication function with Spring Security
Create Spring Cloud Config Server with security with Spring Boot 2.0
Execute arbitrary processing after Basic authentication with Spring boot.
About Spring Security authentication
Spring Cloud Netflix Note
Spring with Kotorin --- 5. Actuator
Let's write a proxy integrated Lambda function of Amazon API Gateway with Spring Cloud Function
Microservices in Spring Cloud
Self-made Validation with Spring
Spring with Kotorin ―― 1. SPRING INITIALIZR
Download with Spring Boot
Search AWS S3 resources with Spring Cloud AWS Resource Handling feature
Generate barcode with Spring Boot
Hello World with Spring Boot
Java Config with Spring MVC
Implement GraphQL with Spring Boot
Spring with Kotorin --8 Repository layer
Get started with Spring boot
Spring Cloud Stream demo released
Run LIFF with Spring Boot
SNS login with Spring Boot
File upload with Spring Boot
Spring Boot starting with copy
Spring with Kotorin ―― 7. Service layer
Login function with Spring Security
Using Mapper with Java (Spring)
Spring Boot starting with Docker
Hello World with Spring Boot
Set cookies with Spring Boot
Use Spring JDBC with Spring Boot
Add module with Spring Boot
Getting Started with Spring Boot
Link API with Spring + Vue.js
Create microservices with Spring Boot
Send email with spring boot
Intent-filter does not respond with callback URL of Twitter OAuth authentication
I get a 404 error when testing forms authentication with Spring Security
Part 1: Try using OAuth 2.0 Login supported by Spring Security 5 with Spring Boot