我有一个使用SpringBoot,Jersey2和Keycloak构建的API。我使用的是SpringBoot适配器以及SpringAdapter。一切都很好。
我现在偶然发现了这个页面https://github.com/swagger-api/swagger-core/wiki/Swagger-Core-Jersey-2.X-Project-Setup-1.5
并开始使用swagger-core包为我的API生成swagger.json
文件。 swagger-jersey2依赖项会在swagger.json
这样的链接中公开http://localhost:8080/swagger.json
文件:SecurityConfig
。但是,我无法公开访问该网址,因为密钥泄露会阻止它。
在我的public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter
{
//....other code above
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.csrf().disable().authorizeRequests().antMatchers("*").permitAll();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
课程中,我有以下内容:
swagger.json
如何更改配置以允许访问Interface
而无需传递承载令牌? (我测试了使用不记名令牌进行访问,但它工作正常,但我需要在没有持票人令牌的情况下访问它)
答案 0 :(得分:1)
我最后通过以下方式解决了这个问题:
PubliResource
注释。PublicResource
注释的类创建了一个列表,然后显式地让请求投放在这些类上,即使没有检测到令牌。import java.lang.annotation.*;
/***
* Used for marking a class accessible to a non-authorized user for
* @GET, @PUT, @POST, and @DELETE annotations
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface PublicResource {
}
然后我做了一个AuthenticationTokenProcessingFilter
bean。
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.AdapterUtils;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.representations.AccessToken;
import org.reflections.Reflections;
import org.reflections.util.ConfigurationBuilder;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.*;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Set;
import java.util.TreeSet;
public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
private static Set<String> nonAuthenticationWhiteListSet = new TreeSet<>();
static {
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.forPackages("com.package.code.resources"); //IMPORTANT
Reflections reflections = new Reflections(configurationBuilder);
Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(PublicResource.class);
for (Class<?> annotatedClass : annotated) {
if (!annotatedClass.isAnnotationPresent(Path.class)) {
continue;
}
String classPath = annotatedClass.getAnnotation(Path.class).value();
for (Method method : annotatedClass.getDeclaredMethods()) {
String fullPath = classPath;
if (method.isAnnotationPresent(GET.class)
|| method.isAnnotationPresent(POST.class)
|| method.isAnnotationPresent(PUT.class)
|| method.isAnnotationPresent(DELETE.class)) {
if (method.isAnnotationPresent(Path.class)) {
fullPath += method.getDeclaredAnnotation(Path.class).value();
}
fullPath = fullPath.replaceAll("\\{.*\\}", "[^/]+");
nonAuthenticationWhiteListSet.add(fullPath);
}
}
}
}
public AuthenticationTokenProcessingFilter() {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (!(request instanceof HttpServletRequest)) {
throw new RuntimeException("Expecting a HTTP request");
}
RefreshableKeycloakSecurityContext context = (RefreshableKeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
if (context == null) {
handleNoSecurityContext(request, response, chain);
return;
}
chain.doFilter(request, response);
}
private void handleNoSecurityContext(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String path = httpRequest.getPathInfo();
if (isPublicResource(path)) {
chain.doFilter(request, response);
return;
}
((HttpServletResponse) response).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
private boolean isPublicResource(String path) {
for (String regex : nonAuthenticationWhiteListSet) {
if (path.matches(regex)) {
return true;
}
}
return false;
}
}
然后在我的主要课程中我做了这个,所以它会被注册为过滤器。
@Configuration
@EnableAutoConfiguration(exclude = {FallbackWebSecurityAutoConfiguration.class, SpringBootWebSecurityConfiguration.class, DataSourceAutoConfiguration.class})
@ComponentScan
@EnableAsync
public class MyApi {
//...other code plus the main method
@Bean
public AuthenticationTokenProcessingFilter authFilter() {
return new AuthenticationTokenProcessingFilter();
}
}