Spring Boot 404返回404错误

j8ag8udp  于 2022-11-23  发布在  Spring
关注(0)|答案(1)|浏览(264)

我正在使用Sping Boot Keycloak 17将单片应用程序现代化为基于微服务的应用程序,支持多租户,配置是Keycloak配置文件,具体取决于指向此example的路径
对我来说,它工作正常,可以从json加载部署,登录,下面是应用程序的url,我正在解析“tenant”后的branch 1,没有问题
http://localhost:8100/租户/分支机构1/

主要问题是呈现css和JS文件,这些文件包含租户名称,知道我在多个领域中使用sing WAR

http://localhost:8100/tenant/branch1/resources/bootstrap/js/bootstrap.min.js--〉返回不存在404

  • 包含静态内容的实际代码 *

在jsp文件中,我像以前一样阅读css/js文件<link rel="stylesheet" href="resources/bootstrap/css/bootstrap.min.css">

  • keycloal json文件示例 *
{"realm": "branch1",
 "auth-server-url": "http://localhost:8181/",
 "ssl-required": "external",
 "resource": "app",
 "public-client": true,
 "confidential-port": 0,
 "principal-attribute": "preferred_username"}

请告知

1.呈现静态内容
1.在身份验证后返回一个不带tenant/branch 1的URL是否有任何指导,特别是我在应用程序中使用CurrentTenantIdentifierResolver
@ConditionalOnProperty(前缀=“密钥隐藏.配置”,名称=“解析器”,值=“路径”)公共类PathBasedConfigResolver实现密钥隐藏配置解析器{

private final ConcurrentHashMap<String, KeycloakDeployment> cache = new ConcurrentHashMap<>();

    @SuppressWarnings("unused")
    private static AdapterConfig adapterConfig;

    @Override
    public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {

        System.out.println("inside resolve :: ");
        String realm = SubdomainUtils.obtainTenantFromSubdomain(request.getURI());

        if (realm.contains("?")) {
            realm = realm.split("\\?")[0];
        }

        if (!cache.containsKey(realm)) {
            InputStream is = this.getClass().getResourceAsStream("/" + realm + "-keycloak.json");
            cache.put(realm, KeycloakDeploymentBuilder.build(is));
        }

        return cache.get(realm);
    }

    static void setAdapterConfig(AdapterConfig adapterConfig) {
        PathBasedConfigResolver.adapterConfig = adapterConfig;
    }

}

public class SpringKeycloakSecurityConfiguration {

@DependsOn("keycloakConfigResolver")
@KeycloakConfiguration
    @ConditionalOnProperty(name = "keycloak.enabled", havingValue = "true", matchIfMissing = true)
    public static class KeycloakConfigurationAdapter extends KeycloakWebSecurityConfigurerAdapter {

        /**
     * Registers the KeycloakAuthenticationProvider with the authentication manager.
     */
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
        SimpleAuthorityMapper soa = new SimpleAuthorityMapper();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(soa);
        auth.authenticationProvider(keycloakAuthenticationProvider);
    }

    /**
     * Defines the session authentication strategy.
     */
    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        // required for bearer-only applications.
        // return new NullAuthenticatedSessionStrategy();
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
    }

    @Override
    protected AuthenticationEntryPoint authenticationEntryPoint() throws Exception {
        return new MultitenantKeycloakAuthenticationEntryPoint(adapterDeploymentContext());
    }

    @Override
    protected KeycloakAuthenticationProcessingFilter keycloakAuthenticationProcessingFilter() throws Exception {
        KeycloakAuthenticationProcessingFilter filter = new KeycloakAuthenticationProcessingFilter(
                authenticationManager(), new AntPathRequestMatcher("/tenant/*/sso/login"));
        filter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy());
        return filter;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean(
            KeycloakAuthenticationProcessingFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean(
            KeycloakPreAuthActionsFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public FilterRegistrationBean keycloakAuthenticatedActionsFilterBean(
            KeycloakAuthenticatedActionsFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public FilterRegistrationBean keycloakSecurityContextRequestFilterBean(
            KeycloakSecurityContextRequestFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @Bean
    @Override
    @ConditionalOnMissingBean(HttpSessionManager.class)
    protected HttpSessionManager httpSessionManager() {
        return new HttpSessionManager();
    }

    /**
     * Configuration spécifique à keycloak (ajouts de filtres, etc)
     * 
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement()
                // use previously declared bean
                .sessionAuthenticationStrategy(sessionAuthenticationStrategy())

                // keycloak filters for securisation
                .and().addFilterBefore(keycloakPreAuthActionsFilter(), LogoutFilter.class)
                .addFilterBefore(keycloakAuthenticationProcessingFilter(), X509AuthenticationFilter.class)
                .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())

                .and().logout().addLogoutHandler(keycloakLogoutHandler()).logoutUrl("/tenant/*/logout")
                .logoutSuccessHandler(
                        // logout handler for API
                        (HttpServletRequest request, HttpServletResponse response,
                                Authentication authentication) -> response.setStatus(HttpServletResponse.SC_OK))
                .and().authorizeRequests().antMatchers("mobileservlet/**").permitAll().antMatchers("**/favicon.ico")
                .permitAll().antMatchers("/error").permitAll().antMatchers("/login.go").permitAll()
                .antMatchers("/resources/*").permitAll().anyRequest().authenticated();

    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList(HttpMethod.OPTIONS.name(), "GET", "POST"));
        configuration.setAllowedHeaders(
                Arrays.asList("Access-Control-Allow-Headers", "Access-Control-Allow-Origin", "Authorization"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

}

public class MultitenantKeycloakAuthenticationEntryPoint extends KeycloakAuthenticationEntryPoint {

public MultitenantKeycloakAuthenticationEntryPoint(AdapterDeploymentContext adapterDeploymentContext) {
    super(adapterDeploymentContext);
}

public MultitenantKeycloakAuthenticationEntryPoint(AdapterDeploymentContext adapterDeploymentContext, RequestMatcher apiRequestMatcher) {
    super(adapterDeploymentContext, apiRequestMatcher);
}

@Override
protected void commenceLoginRedirect(HttpServletRequest request, HttpServletResponse response) throws IOException {

    System.out.println("inside commenceLoginRedirect :: ");
    
    String path = request.getRequestURI();
    int multitenantIndex = path.indexOf("tenant/");
    if (multitenantIndex == -1) {
        throw new IllegalStateException("Not able to resolve the realm from the request path!");
    }

    String realm = path.substring(path.indexOf("tenant/")).split("/")[1];
    if (realm.contains("?")) {
        realm = realm.split("\\?")[0];
    }

    String contextAwareLoginUri = request.getContextPath() + "/tenant/" + realm + DEFAULT_LOGIN_URI;
    response.sendRedirect(contextAwareLoginUri);
}

}

g52tjvyc

g52tjvyc1#

坏消息是,你正在使用的Spring的Keycloak适配器非常deprecated。不要使用它。
更好的消息是,我托管了支持多租户的spring-boot starters for resource-servers:接受由多个颁发者颁发的身份(根据您的情况需要多个领域),并使用您想要的Map(控制大小写和前缀)从领域和客户端检索“角色”。它还允许您从属性文件配置“公共”路由和CORS配置(以及其他一些内容)。
两个客户端(some clientother-client)使用的realm1other-realm的配置非常简单:
第一个

相关问题