Oauth 招摇过市中的KeyClope集成
我有一个受keydove保护的后端,我想通过swagger用户界面访问它。KeyClope提供oauth2隐式和访问代码流,但我无法使其工作。目前,关于swagger.json中的authorizationUrl和tokenUrl应该使用哪个url,Keyclope的文档还很缺乏 Key斗篷中的每个领域都通过访问提供了一个庞大的配置URL列表 此外,我还尝试通过添加以下几行代码,在swagger ui index.html中直接集成keydape js客户端:Oauth 招摇过市中的KeyClope集成,oauth,swagger,swagger-ui,keycloak,jboss-tools,Oauth,Swagger,Swagger Ui,Keycloak,Jboss Tools,我有一个受keydove保护的后端,我想通过swagger用户界面访问它。KeyClope提供oauth2隐式和访问代码流,但我无法使其工作。目前,关于swagger.json中的authorizationUrl和tokenUrl应该使用哪个url,Keyclope的文档还很缺乏 Key斗篷中的每个领域都通过访问提供了一个庞大的配置URL列表 此外,我还尝试通过添加以下几行代码,在swagger ui index.html中直接集成keydape js客户端: <script src="k
<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>
但它也不起作用
有没有关于如何在swagger中集成KeyClope auth的建议?swagger ui可以使用
隐式
身份验证模式与KeyClope集成。
您可以在swagger ui上设置oauth2,这样它将要求您进行身份验证,而不是直接向swagger ui提供访问令牌
首先,您的炫耀需要引用安全定义,如:
"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"
}
}
}
然后,您需要引用一些其他参数:对于纯js,您可以在index.html
const ui = SwaggerUIBundle({ ...} );
ui.initOAuth({
clientId: "test-uid",
realm: "Master",
appName: "swagger-ui",
scopeSeparator: " ",
additionalQueryStringParams: {"nonce": "132456"}
})
在这部法典中
是您的KeyClope域上的授权端点authorizationUrl
- 范围是可以根据需要设置的
是一个客户端,在KeyClope域上使用clientId
模式参数化implicit
- 额外的参数
应该是随机的,但是swagger ui还没有使用它nonce
<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>
然后您可以像这样设置配置类:
@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;
}
}
@配置
公共类配置器{
@豆子
公共安全配置SecurityConfiguration(){
Map additionalQueryStringParams=new HashMap();
附加QueryStringParams.put(“nonce”、“123456”);
返回SecurityConfiguration builder.builder()
.clientId(“测试uid”).realm(“主控”).appName(“炫耀ui”)
.additionalQueryStringParams(additionalQueryStringParams)
.build();
}
@豆子
公开摘要api(){
返回新摘要(DocumentationType.SWAGGER_2)
.选择()
.api(RequestHandlerSelectors.basePackage(“com.example.testspring”))
.path(路径选择器.any())
.build().SecurityScheme(buildSecurityScheme()).SecurityContext(buildSecurityContext());
}
私有列表buildSecurityContext(){
List securityReferences=new ArrayList();
securityReferences.add(SecurityReference.builder().reference(“oauth2”).scopes(scopes().toArray(new AuthorizationScope[]{})).build());
SecurityContext context=SecurityContext.builder().forpath(Predicates.alwaysTrue()).securityReferences(securityReferences.build();
List ret=new ArrayList();
ret.add(上下文);
返回ret;
}
private List在过去的两天里一直在努力进行此设置。终于为无法解决此问题的用户找到了一个有效的解决方案
pom.xml
...
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-security-adapter</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
</dependency>
...
SwaggerConfig.java
package com.XXX.XXXXXXXX.app.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.AuthorizationCodeGrantBuilder;
import springfox.documentation.builders.OAuthBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
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 springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.Arrays;
import static springfox.documentation.builders.PathSelectors.regex;
/*
* Setting up Swagger for spring boot
* https://www.baeldung.com/swagger-2-documentation-for-spring-rest-api
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Value("${keycloak.auth-server-url}")
private String AUTH_SERVER;
@Value("${keycloak.credentials.secret}")
private String CLIENT_SECRET;
@Value("${keycloak.resource}")
private String CLIENT_ID;
@Value("${keycloak.realm}")
private String REALM;
private static final String OAUTH_NAME = "spring_oauth";
private static final String ALLOWED_PATHS = "/directory_to_controllers/.*";
private static final String GROUP_NAME = "XXXXXXX-api";
private static final String TITLE = "API Documentation for XXXXXXX Application";
private static final String DESCRIPTION = "Description here";
private static final String VERSION = "1.0";
@Bean
public Docket taskApi() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName(GROUP_NAME)
.useDefaultResponseMessages(true)
.apiInfo(apiInfo())
.select()
.paths(regex(ALLOWED_PATHS))
.build()
.securitySchemes(Arrays.asList(securityScheme()))
.securityContexts(Arrays.asList(securityContext()));
}
private ApiInfo apiInfo() {
return new
ApiInfoBuilder().title(TITLE).description(DESCRIPTION).version(VERSION).build();
}
@Bean
public SecurityConfiguration security() {
return SecurityConfigurationBuilder.builder()
.realm(REALM)
.clientId(CLIENT_ID)
.clientSecret(CLIENT_SECRET)
.appName(GROUP_NAME)
.scopeSeparator(" ")
.build();
}
private SecurityScheme securityScheme() {
GrantType grantType =
new AuthorizationCodeGrantBuilder()
.tokenEndpoint(new TokenEndpoint(AUTH_SERVER + "/realms/" + REALM + "/protocol/openid-connect/token", GROUP_NAME))
.tokenRequestEndpoint(
new TokenRequestEndpoint(AUTH_SERVER + "/realms/" + REALM + "/protocol/openid-connect/auth", CLIENT_ID, CLIENT_SECRET))
.build();
SecurityScheme oauth =
new OAuthBuilder()
.name(OAUTH_NAME)
.grantTypes(Arrays.asList(grantType))
.scopes(Arrays.asList(scopes()))
.build();
return oauth;
}
private AuthorizationScope[] scopes() {
AuthorizationScope[] scopes = {
new AuthorizationScope("user", "for CRUD operations"),
new AuthorizationScope("read", "for read operations"),
new AuthorizationScope("write", "for write operations")
};
return scopes;
}
private SecurityContext securityContext() {
return SecurityContext.builder()
.securityReferences(Arrays.asList(new SecurityReference(OAUTH_NAME, scopes())))
.forPaths(PathSelectors.regex(ALLOWED_PATHS))
.build();
}
}
从终端运行“mvnw弹簧引导:运行”
打开浏览器并点击
单击“授权”按钮:
这将提供一个模式来确认您的KeyClope设置
再次单击“授权”按钮。您应该被重定向到登录屏幕
输入并确认凭据后,您将被重定向回完全经过身份验证的Swagger UI。使用隐式流、OpenAPI 3.0模板的Swagger UI+Keyclope(或任何其他OAuth2提供程序):
components:
...
securitySchemes:
my_auth_whatever:
type: oauth2
flows:
implicit:
authorizationUrl: https://MY-KEYCLOAK-HOST/auth/realms/MY-REALM-ID/protocol/openid-connect/auth
scopes: {}
...
security:
- my_auth_whatever: []
确保在您使用的客户端的KeyClope设置中启用了隐式流
一个缺点是,当用户单击Swigger UI中的“授权”按钮时,仍会在模式中要求用户提供客户端id。
用户输入的值可以通过向authorizationUrl添加query param?client_id=YOUR-client-id
来覆盖,但这有点像恶意攻击,模式仍然显示给用户。
在docker中运行swagger ui时,可以向容器提供OAUTH_CLIENT_ID env var,以设置模式的默认CLIENT_ID值。
对于非docker部署,请参考@wargre更改index.html的方法(不确定是否有更好的方法)
对于SwaggerAPI(OpenAPI 2.0)示例参考@wargre答案中的第一个代码片段和此文档:你有没有让它工作过?我面临着同样的问题atm。你想将KeyClope与swagger UI集成吗?你现在有没有用KeyClope保护你的swagger定义?也许我可以从作用域的来源来帮助你?在你的KeyClope中,你有用户/阅读权限/写定义?
...
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@SpringBootApplication
@EnableSwagger2
@EnableAsync
@EnableCaching
public class MainApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MainApplication.class);
app.run(args);
}
}
package com.XXX.XXXXXXXX.app.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.AuthorizationCodeGrantBuilder;
import springfox.documentation.builders.OAuthBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
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 springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.Arrays;
import static springfox.documentation.builders.PathSelectors.regex;
/*
* Setting up Swagger for spring boot
* https://www.baeldung.com/swagger-2-documentation-for-spring-rest-api
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Value("${keycloak.auth-server-url}")
private String AUTH_SERVER;
@Value("${keycloak.credentials.secret}")
private String CLIENT_SECRET;
@Value("${keycloak.resource}")
private String CLIENT_ID;
@Value("${keycloak.realm}")
private String REALM;
private static final String OAUTH_NAME = "spring_oauth";
private static final String ALLOWED_PATHS = "/directory_to_controllers/.*";
private static final String GROUP_NAME = "XXXXXXX-api";
private static final String TITLE = "API Documentation for XXXXXXX Application";
private static final String DESCRIPTION = "Description here";
private static final String VERSION = "1.0";
@Bean
public Docket taskApi() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName(GROUP_NAME)
.useDefaultResponseMessages(true)
.apiInfo(apiInfo())
.select()
.paths(regex(ALLOWED_PATHS))
.build()
.securitySchemes(Arrays.asList(securityScheme()))
.securityContexts(Arrays.asList(securityContext()));
}
private ApiInfo apiInfo() {
return new
ApiInfoBuilder().title(TITLE).description(DESCRIPTION).version(VERSION).build();
}
@Bean
public SecurityConfiguration security() {
return SecurityConfigurationBuilder.builder()
.realm(REALM)
.clientId(CLIENT_ID)
.clientSecret(CLIENT_SECRET)
.appName(GROUP_NAME)
.scopeSeparator(" ")
.build();
}
private SecurityScheme securityScheme() {
GrantType grantType =
new AuthorizationCodeGrantBuilder()
.tokenEndpoint(new TokenEndpoint(AUTH_SERVER + "/realms/" + REALM + "/protocol/openid-connect/token", GROUP_NAME))
.tokenRequestEndpoint(
new TokenRequestEndpoint(AUTH_SERVER + "/realms/" + REALM + "/protocol/openid-connect/auth", CLIENT_ID, CLIENT_SECRET))
.build();
SecurityScheme oauth =
new OAuthBuilder()
.name(OAUTH_NAME)
.grantTypes(Arrays.asList(grantType))
.scopes(Arrays.asList(scopes()))
.build();
return oauth;
}
private AuthorizationScope[] scopes() {
AuthorizationScope[] scopes = {
new AuthorizationScope("user", "for CRUD operations"),
new AuthorizationScope("read", "for read operations"),
new AuthorizationScope("write", "for write operations")
};
return scopes;
}
private SecurityContext securityContext() {
return SecurityContext.builder()
.securityReferences(Arrays.asList(new SecurityReference(OAUTH_NAME, scopes())))
.forPaths(PathSelectors.regex(ALLOWED_PATHS))
.build();
}
}
components:
...
securitySchemes:
my_auth_whatever:
type: oauth2
flows:
implicit:
authorizationUrl: https://MY-KEYCLOAK-HOST/auth/realms/MY-REALM-ID/protocol/openid-connect/auth
scopes: {}
...
security:
- my_auth_whatever: []