JAVA-18113 Update spring-boot-swagger-keycloak module (#13506)
* JAVA-18113 Update spring-boot-swagger-keycloak module
This commit is contained in:
@@ -1,75 +1,72 @@
|
||||
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-boot-swagger-keycloak</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<name>spring-boot-swagger-keycloak</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>Module For Spring Boot Swagger UI with Keycloak</description>
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-boot-swagger-keycloak</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<name>spring-boot-swagger-keycloak</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>Module For Spring Boot Swagger UI with Keycloak</description>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung.spring-boot-modules</groupId>
|
||||
<artifactId>spring-boot-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-3</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../parent-boot-3</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.bom</groupId>
|
||||
<artifactId>keycloak-adapter-bom</artifactId>
|
||||
<version>${keycloak.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-bom</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
<scope>import</scope>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-bom</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
<scope>import</scope>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-boot-starter</artifactId>
|
||||
<version>${springfox.version}</version>
|
||||
</dependency>
|
||||
<!-- Authentication with with Keycloak -->
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- Authorization with MethodSecurity (@Secured) - optional -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
|
||||
</dependency>
|
||||
<!-- Authorization with MethodSecurity (@Secured) - optional -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<version>${springdoc.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
<version>${javax.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<spring-boot.version>2.4.5</spring-boot.version>
|
||||
<springfox.version>3.0.0</springfox.version>
|
||||
<keycloak.version>15.0.2</keycloak.version>
|
||||
<log4j2.version>2.17.1</log4j2.version>
|
||||
</properties>
|
||||
<properties>
|
||||
<springdoc.version>2.1.0</springdoc.version>
|
||||
<log4j2.version>2.17.1</log4j2.version>
|
||||
<javax.version>1.3.2</javax.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -1,59 +1,40 @@
|
||||
package com.baeldung.swaggerkeycloak;
|
||||
|
||||
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
|
||||
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
|
||||
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
|
||||
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||
|
||||
@KeycloakConfiguration
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public class GlobalSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
|
||||
public class GlobalSecurityConfig {
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
|
||||
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
|
||||
}
|
||||
|
||||
// otherwise, we'll get an error 'permitAll only works with HttpSecurity.authorizeRequests()'
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
super.configure(http);
|
||||
http
|
||||
.csrf().disable()
|
||||
.authorizeRequests()
|
||||
// we can set up authorization here alternatively to @Secured methods
|
||||
.antMatchers(HttpMethod.OPTIONS).permitAll()
|
||||
.antMatchers("/api/**").authenticated()
|
||||
// force authentication for all requests (and use global method security)
|
||||
.anyRequest().permitAll();
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http.csrf()
|
||||
.disable()
|
||||
.authorizeRequests()
|
||||
.requestMatchers(HttpMethod.OPTIONS)
|
||||
.permitAll()
|
||||
.requestMatchers("/api/**")
|
||||
.authenticated()
|
||||
.anyRequest()
|
||||
.permitAll();
|
||||
http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
|
||||
return http.build();
|
||||
}
|
||||
|
||||
/*
|
||||
* re-configure Spring Security to use
|
||||
* registers the KeycloakAuthenticationProvider with the authentication manager
|
||||
*/
|
||||
@Autowired
|
||||
void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
KeycloakAuthenticationProvider provider = keycloakAuthenticationProvider();
|
||||
provider.setGrantedAuthoritiesMapper(authoritiesMapper());
|
||||
auth.authenticationProvider(provider);
|
||||
}
|
||||
|
||||
GrantedAuthoritiesMapper authoritiesMapper() {
|
||||
SimpleAuthorityMapper mapper = new SimpleAuthorityMapper();
|
||||
mapper.setPrefix("ROLE_"); // Spring Security adds a prefix to the authority/role names (we use the default here)
|
||||
mapper.setConvertToUpperCase(true); // convert names to uppercase
|
||||
mapper.setDefaultAuthority("ROLE_ANONYMOUS"); // set a default authority
|
||||
return mapper;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.baeldung.swaggerkeycloak;
|
||||
|
||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class KeycloakConfigResolverConfig {
|
||||
|
||||
/*
|
||||
* re-configure keycloak adapter for Spring Boot environment,
|
||||
* i.e. to read config from application.yml
|
||||
* (otherwise, we need a keycloak.json file)
|
||||
*/
|
||||
@Bean
|
||||
public KeycloakConfigResolver configResolver() {
|
||||
return new KeycloakSpringBootConfigResolver();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,22 +1,17 @@
|
||||
package com.baeldung.swaggerkeycloak;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import springfox.documentation.builders.OAuth2SchemeBuilder;
|
||||
import springfox.documentation.service.AuthorizationScope;
|
||||
import springfox.documentation.service.SecurityReference;
|
||||
import springfox.documentation.service.SecurityScheme;
|
||||
import springfox.documentation.spi.service.contexts.SecurityContext;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import springfox.documentation.swagger.web.SecurityConfiguration;
|
||||
import springfox.documentation.swagger.web.SecurityConfigurationBuilder;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import io.swagger.v3.oas.models.Components;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import io.swagger.v3.oas.models.security.OAuthFlow;
|
||||
import io.swagger.v3.oas.models.security.OAuthFlows;
|
||||
import io.swagger.v3.oas.models.security.Scopes;
|
||||
import io.swagger.v3.oas.models.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.models.security.SecurityScheme;
|
||||
|
||||
@Configuration
|
||||
public class OpenAPISecurityConfig {
|
||||
@@ -25,59 +20,35 @@ public class OpenAPISecurityConfig {
|
||||
String authServerUrl;
|
||||
@Value("${keycloak.realm}")
|
||||
String realm;
|
||||
@Value("${keycloak.resource}")
|
||||
private String clientId;
|
||||
@Value("${keycloak.credentials.secret}")
|
||||
private String clientSecret;
|
||||
|
||||
@Autowired
|
||||
void addSecurity(Docket docket) {
|
||||
docket
|
||||
.securitySchemes(Collections.singletonList(authenticationScheme()))
|
||||
.securityContexts(Collections.singletonList(securityContext()));
|
||||
}
|
||||
|
||||
private SecurityScheme authenticationScheme() {
|
||||
return new OAuth2SchemeBuilder("implicit")
|
||||
.name("my_oAuth_security_schema")
|
||||
.authorizationUrl(authServerUrl + "/realms/" + realm)
|
||||
.scopes(authorizationScopes())
|
||||
.build();
|
||||
}
|
||||
|
||||
private List<AuthorizationScope> authorizationScopes() {
|
||||
return Arrays.asList(
|
||||
new AuthorizationScope("read_access", "read data"),
|
||||
new AuthorizationScope("write_access", "modify data")
|
||||
);
|
||||
}
|
||||
|
||||
private SecurityContext securityContext() {
|
||||
return SecurityContext.
|
||||
builder().
|
||||
securityReferences(readAccessAuth())
|
||||
.operationSelector(operationContext -> HttpMethod.GET.equals(operationContext.httpMethod()))
|
||||
.build();
|
||||
}
|
||||
|
||||
private List<SecurityReference> readAccessAuth() {
|
||||
AuthorizationScope[] authorizationScopes = new AuthorizationScope[] { authorizationScopes().get(0) };
|
||||
return Collections.singletonList(
|
||||
new SecurityReference("my_oAuth_security_schema", authorizationScopes)
|
||||
);
|
||||
}
|
||||
private static final String OAUTH_SCHEME_NAME = "my_oAuth_security_schema";
|
||||
|
||||
@Bean
|
||||
public SecurityConfiguration security() {
|
||||
return SecurityConfigurationBuilder.builder()
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.realm(realm)
|
||||
.appName(clientId)
|
||||
.scopeSeparator(",")
|
||||
.additionalQueryStringParams(null)
|
||||
.useBasicAuthenticationWithAccessCodeGrant(false)
|
||||
.build();
|
||||
public OpenAPI openAPI() {
|
||||
return new OpenAPI().components(new Components()
|
||||
.addSecuritySchemes(OAUTH_SCHEME_NAME, createOAuthScheme()))
|
||||
.addSecurityItem(new SecurityRequirement().addList(OAUTH_SCHEME_NAME))
|
||||
.info(new Info().title("Todos Management Service")
|
||||
.description("A service providing todos.")
|
||||
.version("1.0"));
|
||||
}
|
||||
|
||||
private SecurityScheme createOAuthScheme() {
|
||||
OAuthFlows flows = createOAuthFlows();
|
||||
return new SecurityScheme().type(SecurityScheme.Type.OAUTH2)
|
||||
.flows(flows);
|
||||
}
|
||||
|
||||
private OAuthFlows createOAuthFlows() {
|
||||
OAuthFlow flow = createAuthorizationCodeFlow();
|
||||
return new OAuthFlows().implicit(flow);
|
||||
}
|
||||
|
||||
private OAuthFlow createAuthorizationCodeFlow() {
|
||||
return new OAuthFlow()
|
||||
.authorizationUrl(authServerUrl + "/realms/" + realm + "/protocol/openid-connect/auth")
|
||||
.scopes(new Scopes().addString("read_access", "read data")
|
||||
.addString("write_access", "modify data"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
package com.baeldung.swaggerkeycloak;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.oas.annotations.EnableOpenApi;
|
||||
import springfox.documentation.service.ApiInfo;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
|
||||
import static springfox.documentation.builders.RequestHandlerSelectors.basePackage;
|
||||
|
||||
@EnableOpenApi
|
||||
@Configuration
|
||||
class SwaggerUIConfig {
|
||||
|
||||
@Bean
|
||||
Docket api() {
|
||||
return new Docket(DocumentationType.OAS_30)
|
||||
.useDefaultResponseMessages(false)
|
||||
.select()
|
||||
.apis(basePackage(TodosApplication.class.getPackage().getName()))
|
||||
.paths(PathSelectors.any())
|
||||
.build()
|
||||
.apiInfo(apiInfo());
|
||||
}
|
||||
|
||||
private ApiInfo apiInfo() {
|
||||
return new ApiInfoBuilder().title("Todos Management Service")
|
||||
.description("A service providing todos.")
|
||||
.version("1.0")
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
package com.baeldung.swaggerkeycloak;
|
||||
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiResponse;
|
||||
import io.swagger.annotations.ApiResponses;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collection;
|
||||
@@ -28,13 +29,10 @@ public class TodosController {
|
||||
}
|
||||
|
||||
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ApiOperation("Read all todos")
|
||||
@ApiResponses({
|
||||
@ApiResponse(code = 200, message = "The todos were found and returned.")
|
||||
})
|
||||
@Operation(description = "Read all todos")
|
||||
@ApiResponses({ @ApiResponse(responseCode = "200", description = "The todos were found and returned.") })
|
||||
@PreAuthorize("hasAuthority('SCOPE_read_access')")
|
||||
public Collection<Todo> readAll() {
|
||||
return todos.values();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 665 B |
Binary file not shown.
|
Before Width: | Height: | Size: 628 B |
@@ -1,75 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<title>Swagger UI: OAuth2 Redirect</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
'use strict';
|
||||
function run () {
|
||||
var oauth2 = window.opener.swaggerUIRedirectOauth2;
|
||||
var sentState = oauth2.state;
|
||||
var redirectUrl = oauth2.redirectUrl;
|
||||
var isValid, qp, arr;
|
||||
|
||||
if (/code|token|error/.test(window.location.hash)) {
|
||||
qp = window.location.hash.substring(1);
|
||||
} else {
|
||||
qp = location.search.substring(1);
|
||||
}
|
||||
|
||||
arr = qp.split("&");
|
||||
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
|
||||
qp = qp ? JSON.parse('{' + arr.join() + '}',
|
||||
function (key, value) {
|
||||
return key === "" ? value : decodeURIComponent(value);
|
||||
}
|
||||
) : {};
|
||||
|
||||
isValid = qp.state === sentState;
|
||||
|
||||
if ((
|
||||
oauth2.auth.schema.get("flow") === "accessCode" ||
|
||||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
|
||||
oauth2.auth.schema.get("flow") === "authorization_code"
|
||||
) && !oauth2.auth.code) {
|
||||
if (!isValid) {
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
source: "auth",
|
||||
level: "warning",
|
||||
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
|
||||
});
|
||||
}
|
||||
|
||||
if (qp.code) {
|
||||
delete oauth2.state;
|
||||
oauth2.auth.code = qp.code;
|
||||
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
|
||||
} else {
|
||||
let oauthErrorMsg;
|
||||
if (qp.error) {
|
||||
oauthErrorMsg = "["+qp.error+"]: " +
|
||||
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
|
||||
(qp.error_uri ? "More info: "+qp.error_uri : "");
|
||||
}
|
||||
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
source: "auth",
|
||||
level: "error",
|
||||
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
|
||||
});
|
||||
}
|
||||
} else {
|
||||
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
|
||||
}
|
||||
window.close();
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', function () {
|
||||
run();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,8 +1,19 @@
|
||||
server:
|
||||
port: 8081
|
||||
|
||||
keycloak:
|
||||
auth-server-url: https://api.example.com/auth # Keycloak server url
|
||||
realm: todos-service-realm # Keycloak Realm
|
||||
resource: todos-service-clients # Keycloak Client
|
||||
principal-attribute: preferred_username
|
||||
ssl-required: external
|
||||
credentials:
|
||||
secret: 00000000-0000-0000-0000-000000000000
|
||||
auth-server-url: http://localhost:8080 # Keycloak server url
|
||||
realm: SpringBootKeycloak # Keycloak Realm
|
||||
|
||||
spring:
|
||||
security:
|
||||
oauth2:
|
||||
resourceserver:
|
||||
jwt.issuer-uri: http://localhost:8080/realms/SpringBootKeycloak
|
||||
|
||||
springdoc:
|
||||
swagger-ui:
|
||||
oauth:
|
||||
client-id: login-app
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user