我将此依赖项添加到我的 Spring Boot 应用程序中
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.4.3</version>
<type>pom.sha512</type>
</dependency>
然后我就可以打开: https://localhost:8443/v3/api-docs
浏览器确实会要求我提供凭据,只要我正确输入用户/密码,它就可以工作,但它会向我显示全局可用的所有方法。我只希望用户有权使用的方法出现在 api 文档中。
具体方法是使用此标签来授权我的调用:
@PreAuthorize("hasRole('USER') OR hasRole('ADMIN')")
这是我的网络安全配置类:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.inMemoryAuthentication()
.passwordEncoder(new BCryptPasswordEncoder())
.withUser("user").password(new BCryptPasswordEncoder().encode("blabl")).roles("USER")
.and()
.withUser("admin").password(new BCryptPasswordEncoder().encode("blabla")).roles("ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception
{
http.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic();
}
}
我怀疑这是否可能,因为 API 文档是在启动时生成的(我认为)。
您可以做的是添加文档,指定哪些 API 调用需要哪些安全凭证,我在 https://github.com/springdoc/springdoc-openapi#adding-api-information-and 发现了这一点-安全文档
因此,如果用户能够看到 API 页面,那么它也可能会看到它无权访问的端点(例如 /admin),但您可以向其中添加文档,说明该端点只能由管理员访问。
根据您提供的描述,我会推荐以下内容。
例如:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/rest/admin/**").hasAnyRole("ADMIN").and()
.httpBasic()
.and()
.csrf().disable();
}
ROLE_
”添加到您的@PreAuthorize
例如:
@PreAuthorize("hasRole('ROLE_USER')")
或
@PreAuthorize("hasRole('ROLE_ADMIN')")
然后它应该按预期工作。
此外,如果它仍然无法按预期工作,我建议为每个角色创建两个单独的
GroupedOpenApi
,并通过超级角色的路径标识符分隔 api(即您的情况下的 ADMIN
)并创建相应的安全性各个 antMatchers 上的配置(例如:.antMatchers("/rest/admin/**").hasAnyRole("ADMIN")
)。
当您在每个角色的路径上配置安全性以及为文档配置单独的 GroupedOpenApi 时,这应该可以工作。
P.S.:我会首先尝试第一种方法,只使用第二种方法作为后备。
基本上,执行此操作的方法是利用
OperationCustomizer
,然后您可以创建条件逻辑,根据角色从文档中排除端点:
import org.springdoc.core.customizers.OperationCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.method.HandlerMethod;
import io.swagger.v3.oas.models.Operation;
@Configuration
public class OpenApiConfig
{
@Bean
public OperationCustomizer operationCustomizer()
{
return (Operation operation, HandlerMethod handlerMethod) ->
{
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.isAuthenticated())
{
PreAuthorize preAuthorize = handlerMethod.getMethodAnnotation(PreAuthorize.class);
if (preAuthorize != null)
{
String[] requiredRoles = preAuthorize.value().replace("hasRole('", "").replace("')", "").split(" OR ");
boolean hasRole = false;
for (GrantedAuthority authority : authentication.getAuthorities())
{
for (String role : requiredRoles)
{
if (authority.getAuthority().equals("ROLE_" + role))
{
hasRole = true;
break;
}
}
if (hasRole)
{
break;
}
}
if (!hasRole)
{
return null; // Exclude the operation if the user does not have any of the required roles
}
}
} else
{
System.out.println("No authenticated user found.");
return null;
}
return operation;
};
}
}