带有弹簧安全oauth2resourceserver第二安全过滤链的弹簧核心不活动

问题描述 投票:0回答:1

package edu.remad.tutoring2.security.config; import java.util.HashMap; import java.util.Map; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.DelegatingPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration @EnableWebSecurity(debug = true) @EnableMethodSecurity public class SpringSecurityConfig { @Value("${spring.websecurity.debug:true}") boolean webSecurityDebug; @Bean WebSecurityCustomizer webSecurityCustomizer() { return (web) -> web.debug(webSecurityDebug); } @Bean PasswordEncoder passwordEncoder() { String idForEncode = "bcrypt"; Map<String, PasswordEncoder> encoders = new HashMap<>(); encoders.put(idForEncode, new BCryptPasswordEncoder()); return new DelegatingPasswordEncoder(idForEncode, encoders); } }

SecurityFilterConfig.java:

    package edu.remad.tutoring2.security.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.HeaderWriterLogoutHandler;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.header.HeaderWriterFilter;
import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter;
import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import edu.remad.tutoring2.jwt.Tutoring2CustomJwtAuthenticationConverter;
import edu.remad.tutoring2.security.ContentSecurityPolicySettings;
import edu.remad.tutoring2.security.filters.DebugLoggingFilter;
import edu.remad.tutoring2.security.filters.HttpHeadersFilter;
import edu.remad.tutoring2.security.filters.TenantFilter;

@Configuration
public class SecurityFilterChainsConfig {

    private static final ClearSiteDataHeaderWriter.Directive[] COOKIES = Directive.values();

    @Autowired
    private ContentSecurityPolicySettings contentSecurityPolicies;

    @Autowired
    private Tutoring2CustomJwtAuthenticationConverter jwtAuthConverter;

    /**
     * Does form login filter chain and has also http security.
     * 
     * @param http similar to spring security xml config for filtering request
     * @return created security filter chain, {@link SecurityFilterChain}
     * @throws Exception
     */
    @Bean
    @Order(1)
    SecurityFilterChain formloginSecurityFilterChain(HttpSecurity http) throws Exception {
        http.cors().and().headers(headers -> headers.xssProtection().and()
                .contentSecurityPolicy(contentSecurityPolicies.getContentSecurityPolicies()));

        http.addFilterAfter(new TenantFilter(), BasicAuthenticationFilter.class)
                .addFilterAfter(new HttpHeadersFilter(), HeaderWriterFilter.class)
                .addFilterAfter(new DebugLoggingFilter(), HttpHeadersFilter.class)
                .securityContext((securityContext) -> securityContext.requireExplicitSave(true))
                .sessionManagement(
                        session -> session.maximumSessions(1).maxSessionsPreventsLogin(true).expiredUrl("/login"))
                .authorizeRequests(requests -> requests.antMatchers("/", "/helloWorld", "/logoutSuccess", "/signup", "/api/v1/csrf")
                        .permitAll().antMatchers("/hello", "/bye", "/login", "/logout", "/templates/**").authenticated())
                .formLogin(login -> login.loginPage("/myCustomLogin").loginProcessingUrl("/process-login")
                        .defaultSuccessUrl("/hello", true)).csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
                .logout(logout -> logout.logoutUrl("/logout").logoutSuccessUrl("/logoutSuccess")
                        .addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(COOKIES))));

        return http.build();
    }

    @Bean
    @Order(2)
    SecurityFilterChain oauth2rescourceserverSecurityFilterChain(HttpSecurity http) throws Exception {
        return http.securityMatcher(AntPathRequestMatcher.antMatcher("/v2/**"))
                .authorizeHttpRequests(requests -> requests.anyRequest().authenticated()).csrf(csrf -> csrf.disable())
                .oauth2ResourceServer(server -> server.jwt().jwtAuthenticationConverter(jwtAuthConverter))
                .sessionManagement(management -> management.sessionCreationPolicy(SessionCreationPolicy.STATELESS)).build();
    }
}

oauth2ResourcServerConfig.java:

    package edu.remad.tutoring2.security.config;

import java.net.MalformedURLException;
import java.net.URL;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;

import com.nimbusds.jose.KeySourceException;
import com.nimbusds.jose.proc.JWSAlgorithmFamilyJWSKeySelector;
import com.nimbusds.jose.proc.JWSKeySelector;
import com.nimbusds.jose.proc.SecurityContext;
import com.nimbusds.jwt.proc.DefaultJWTProcessor;

@Configuration
public class Oauth2ResourcServerConfig {

    private String keySetUri = "http://192.168.120.59:8080/realms/ConnectTrial/protocol/openid-connect/certs";

    @Bean
    JwtDecoder jwtDecoder() throws KeySourceException, MalformedURLException {
        JWSKeySelector<SecurityContext> jwsKeySelector =
                JWSAlgorithmFamilyJWSKeySelector.fromJWKSetURL(new URL(keySetUri));

        DefaultJWTProcessor<SecurityContext> jwtProcessor =
                new DefaultJWTProcessor<>();
        jwtProcessor.setJWSKeySelector(jwsKeySelector);

        return new NimbusJwtDecoder(jwtProcessor);
    }

}

Tutoring2customjwtauthenticationconverter.java:

    package edu.remad.tutoring2.jwt;

import static edu.remad.tutoring2.appconstants.JwtAppConstants.JWT_CLAIM_RESSOURCE_ACCESS;
import static edu.remad.tutoring2.appconstants.JwtAppConstants.JWT_CONVERTER_PRINCIPAL_ATTRIBUTE;
import static edu.remad.tutoring2.appconstants.JwtAppConstants.JWT_CONVERTER_RESOURCE_ID;
import static edu.remad.tutoring2.appconstants.JwtAppConstants.JWT_ROLES_KEY;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.NonNull;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtClaimNames;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.stereotype.Component;

/**
 * Converts roles from Keycloak to Spring Security roles. It reads JWT and fetches all claims and roles as roles. 
 */
@Component
public class Tutoring2CustomJwtAuthenticationConverter implements Converter<Jwt, AbstractAuthenticationToken> {

    private final JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter;

    /**
     * Default Constructor
     */
    public Tutoring2CustomJwtAuthenticationConverter() {
        jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
    }

    @Override
    public AbstractAuthenticationToken convert(@NonNull Jwt jwt) {
        Collection<GrantedAuthority> authorities = Stream
                .concat(jwtGrantedAuthoritiesConverter.convert(jwt).stream(), extractJwtResourceRoles(jwt).stream())
                .collect(Collectors.toSet());

        return new JwtAuthenticationToken(jwt, authorities, getPrincipalClaimName(jwt));
    }

    private Collection<? extends GrantedAuthority> extractJwtResourceRoles(Jwt jwt) {
        if (jwt.getClaimAsMap(JWT_CLAIM_RESSOURCE_ACCESS) == null) {
            return Set.of();
        }

        Map<String, Object> resourceAccess = jwt.getClaim("resource_access");
        if (resourceAccess.get(JWT_CONVERTER_RESOURCE_ID) == null) {
            return Set.of();
        }

        if (resourceAccess.get(JWT_CONVERTER_RESOURCE_ID) == null) {
            return Set.of();
        }

        Map<String, Object> resource = (Map<String, Object>) resourceAccess.get(JWT_CONVERTER_RESOURCE_ID);
        Collection<String> resourceRoles = (Collection<String>) resource.get(JWT_ROLES_KEY);

        return resourceRoles.stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role))
                .collect(Collectors.toSet());
    }

    private String getPrincipalClaimName(Jwt jwt) {
        String claimName = JwtClaimNames.SUB;
        
        if (JWT_CONVERTER_PRINCIPAL_ATTRIBUTE != null) {
            claimName = JWT_CONVERTER_PRINCIPAL_ATTRIBUTE;
        }

        return jwt.getClaim(claimName);
    }

}

pom.xml:

    <project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <!-- ###################### -->
    <!-- start of project setup -->
    <!-- ###################### -->
    <modelVersion>4.0.0</modelVersion>
    <groupId>edu.remad</groupId>
    <artifactId>tutoring2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>Tutoring 2 Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <!-- #################### -->
    <!-- end of project setup -->
    <!-- #################### -->

    <!-- ################### -->
    <!-- start of properties -->
    <!-- ################### -->
    <properties>
        <maven.compiler.target>11</maven.compiler.target>
        <maven.compiler.source>11</maven.compiler.source>
        <encoding>UTF-8</encoding>
        <spring.version>5.3.39</spring.version>
        <spring.security.version>5.8.16</spring.security.version>
        <spring.boot.version>2.7.14</spring.boot.version>
        <junit5.version>5.10.0</junit5.version>
        <lombok.version>1.18.30</lombok.version>
        <spring.oauth2.resourceserver.version>2.7.14</spring.oauth2.resourceserver.version>
        <version>3.3.2</version>
    </properties>
    <!-- ################# -->
    <!-- end of properties -->
    <!-- ################# -->

    <!-- ##################### -->
    <!-- start of dependencies -->
    <!-- ##################### -->
    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
        <!-- spring security needed deoendencies -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-resource-server</artifactId>
            <version>5.8.16</version>
        </dependency>

        <!-- Spring framework -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.6.9.Final</version>
        </dependency>
        <!-- Hibernate Validator -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.4.3.Final</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <scope>provided</scope>
        </dependency>
        <!-- CGLib for @Configuration -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib-nodep</artifactId>
            <version>2.2.2</version>
            <scope>runtime</scope>
        </dependency>
        <!-- Servlet Spec -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
        <!--<dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <version>5.0.0</version>
        </dependency>-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>
        <!-- Maven Plugins section -->
        <dependency>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.11.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>3.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>3.1.2</version>
        </dependency>
        <!-- JAXB, for version 3 use Jakarta -->
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.8</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>5.3.2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
            <version>2.16.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
            <version>2.16.0</version>
        </dependency>

        <!-- Testing -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>${junit5.version}</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit5.version}</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit5.version}</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-params</artifactId>
            <version>${junit5.version}</version>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-suite</artifactId>
            <version>1.10.0</version>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>5.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-junit-jupiter</artifactId>
            <version>5.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- resource-server -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
            <version>${spring.oauth2.resourceserver.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>${spring.oauth2.resourceserver.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring.oauth2.resourceserver.version}</version>
        </dependency>

        <!-- start of own implementations -->
        <dependency>
            <groupId>edu.remad</groupId>
            <artifactId>ical4j-builder</artifactId>
            <version>1.0.6-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>edu.remad</groupId>
            <artifactId>pdf-toolboxing</artifactId>
            <version>0.30.1-SNAPSHOT</version>
        </dependency>
        <!-- end of own implementation -->
    </dependencies>
    <!-- ################### -->
    <!-- end of dependencies -->
    <!-- ################### -->

    <!-- ################# -->
    <!-- start of profiles -->
    <!-- ################# -->
    <profiles>
        <profile>
            <id>development</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <maven.test.skip>true</maven.test.skip>
            </properties>
        </profile>
        <profile>
            <id>withoutTests</id>
            <properties>
                <maven.test.skip>true</maven.test.skip>
            </properties>
        </profile>
        <profile>
            <id>withIntegrationTests</id>
            <properties>
            </properties>
        </profile>
    </profiles>

    <!-- ############### -->
    <!-- end of profiles -->
    <!-- ############### -->

    <!-- ###################### -->
    <!-- start of build section -->
    <!-- ###################### -->
    <build>
        <finalName>tutoring2</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>${maven.compiler.target}</source>
                    <target>${maven.compiler.source}</target>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>${lombok.version}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.4.0</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.2.1</version>
                <dependencies>
                    <dependency>
                        <groupId>org.junit.jupiter</groupId>
                        <artifactId>junit-jupiter-engine</artifactId>
                        <version>${junit5.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
    <!-- #################### -->
    <!-- end of build section -->
    <!-- #################### -->
</project>

开关
@Order
java spring-security spring-security-oauth2 spring5 oauth2resourceserver
1个回答
0
投票

@Order

中尝试了安全过滤器链(在2之前尝试了1个)。使用第一个匹配的请求,而其他请求被丢弃。如果没有
securityMatcher

,则滤清器链匹配所有请求,这是最后一个过滤器链的好选择(默认情况下),但对于第一个请求(如在您的conf中)。

在旁注时,您可以找到我有用的ime starter。它将为您节省维护当局转换器和

oauth2ResourceServer
过滤链的负担。但是请注意,由我的入门者自动配置的资源服务器过滤器链没有
securityMatcher
且最低的优先级。因此,除了删除您的

oauth2rescourceserverSecurityFilterChain

Oauth2ResourcServerConfig

Tutoring2CustomJwtAuthenticationConverter
外,您还必须为您的
securityMatcher
定义一个(具有类似于您必须
formloginSecurityFilterChain
的东西)
    

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.