oauth - example - Integración de Keycloak en Swagger
swagger securitydefinitions (1)
Swagger-ui puede integrarse con keycloak usando el modo de autenticación implicit
. Puede configurar oauth2 en swagger-ui para que le solicite que se autentique en lugar de dar el token de acceso directamente a swagger-ui.
En primer lugar, su arrogancia debe hacer referencia a una definición de seguridad como:
"securityDefinitions": {
"oauth2": {
"type":"oauth2",
"authorizationUrl":"http://172.17.0.2:8080/auth/realms/master/protocol/openid-connect/auth",
"flow":"implicit",
"scopes": {
"openid":"openid",
"profile":"profile"
}
}
}
Luego, swagger-ui necesita hacer referencia a algún otro parámetro: con pure js, puede usar en index.html
const ui = SwaggerUIBundle({ ...} );
ui.initOAuth({
clientId: "test-uid",
realm: "Master",
appName: "swagger-ui",
scopeSeparator: " ",
additionalQueryStringParams: {"nonce": "132456"}
})
En este código,
- permissionUrl es el punto final de autorización en su dominio keycloak
- Los alcances son algo que puede configurar a sus necesidades
-
clientId
es un cliente parametrizado con modoimplicit
en el dominio keycloak - el parámetro adicional
nonce
debe ser aleatorio, pero swagger-ui no lo usa todavía.
Tendré un ejemplo si quieres hacer todo esto en Spring-boot:
En este marco, utilizarás principalmente el web-jar swagger y swagger-ui de Springfox. Esto se hace agregando las dependencias:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
Swagger se habilita agregando la anotación swagger2
en su clase principal:
@SpringBootApplication
@EnableSwagger2
public class TestSpringApplication {
...
entonces puedes configurar una clase de Configuration
como esta:
@Configuration
public class SwaggerConfigurer {
@Bean
public SecurityConfiguration securityConfiguration() {
Map<String, Object> additionalQueryStringParams=new HashMap<>();
additionalQueryStringParams.put("nonce","123456");
return SecurityConfigurationBuilder.builder()
.clientId("test-uid").realm("Master").appName("swagger-ui")
.additionalQueryStringParams(additionalQueryStringParams)
.build();
}
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.testspring"))
.paths(PathSelectors.any())
.build().securitySchemes(buildSecurityScheme()).securityContexts(buildSecurityContext());
}
private List<SecurityContext> buildSecurityContext() {
List<SecurityReference> securityReferences = new ArrayList<>();
securityReferences.add(SecurityReference.builder().reference("oauth2").scopes(scopes().toArray(new AuthorizationScope[]{})).build());
SecurityContext context = SecurityContext.builder().forPaths(Predicates.alwaysTrue()).securityReferences(securityReferences).build();
List<SecurityContext> ret = new ArrayList<>();
ret.add(context);
return ret;
}
private List<? extends SecurityScheme> buildSecurityScheme() {
List<SecurityScheme> lst = new ArrayList<>();
// lst.add(new ApiKey("api_key", "X-API-KEY", "header"));
LoginEndpoint login = new LoginEndpointBuilder().url("http://172.17.0.2:8080/auth/realms/master/protocol/openid-connect/auth").build();
List<GrantType> gTypes = new ArrayList<>();
gTypes.add(new ImplicitGrant(login, "acces_token"));
lst.add(new OAuth("oauth2", scopes(), gTypes));
return lst;
}
private List<AuthorizationScope> scopes() {
List<AuthorizationScope> scopes = new ArrayList<>();
for (String scopeItem : new String[]{"openid=openid", "profile=profile"}) {
String scope[] = scopeItem.split("=");
if (scope.length == 2) {
scopes.add(new AuthorizationScopeBuilder().scope(scope[0]).description(scope[1]).build());
} else {
log.warn("Scope ''{}'' is not valid (format is scope=description)", scopeItem);
}
}
return scopes;
}
}
Hay muchas cosas que puedes actualizar en este código. Esto es principalmente lo mismo que antes:
-
nonce
que debería ser aleatorio (swagger-ui no lo usa todavía) -
clientId
que necesita configurar de acuerdo con el cliente que configuró en keycloak -
basePackage
: debe configurar el paquete en el que se encuentran todos los controladores. - Si necesita una clave api, puede habilitarla y agregarla a la lista de esquemas de seguridad
-
LoginEndpoint
: debe ser el punto final de autorización de su dominio keycloak -
scopeItems
: los ámbitos que desea para esta autenticación.
Generará lo mismo que antes: actualizar Swagger para agregar securityDefinition y hacer que swagger-UI tome el parámetro para clientId, nonce, ...
Tengo un backend protegido por Keycloak al que me gustaría acceder a través de swagger-ui. Keycloak en sí mismo proporciona el flujo implícito o accessCode de oauth2, pero ambos no obtuve trabajo. Actualmente, la documentación de Keycloak no se encuentra en ese punto, la url debería usarse para la autorización de usuario y el identificador de token en swagger.json .
Cada reino dentro de Keycloak ofrece una gran lista de url de configuración al acceder a http://keycloak.local/auth/realms/REALM/.well-known/openid-configuration
Además, he intentado integrar directamente el keycloak js-client dentro de swagger-ui index.html agregando las siguientes líneas:
<script src="keycloak/keycloak.js"></script>
<script>
var keycloak = Keycloak(''keycloak.json'');
keycloak.init({ onLoad: ''login-required'' })
.success(function (authenticated) {
console.log(''Login Successful'');
window.authorizations.add("oauth2", new ApiKeyAuthorization("Authorization", "Bearer " + keycloak.token, "header"));
}).error(function () {
console.error(''Login Failed'');
window.location.reload();
}
);
</script>
También probé algo como esto después de ''Iniciar sesión con éxito''
swaggerUi.api.clientAuthorizations.add("key", new SwaggerClient.ApiKeyAuthorization("Authorization", "Bearer " + keycloak.token, "header"));
Pero tampoco funciona.
¿Alguna sugerencia de cómo puedo integrar la autenticación keycloak dentro de swagger?