8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

Spring 中 RedisTemplate bean 具有相同名称的问题

pineconesundae 2月前

51 0

为什么手动声明一个和Spring提供的RedisTemplate同名的bean不会冲突,而且可以正确的获取自己声明的bean来使用呢?

为什么手动声明一个和Spring提供的RedisTemplate同名的RedisTemplate bean不会冲突,而且可以正确的获取自己声明的bean来使用。

没有手动声明的时候是可以正常获取的,说明用的是Spring,但是它本身不支持同名的bean,为什么可以手动声明一个名为\'redisTemplate\'的bean

帖子版权声明 1、本帖标题:Spring 中 RedisTemplate bean 具有相同名称的问题
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由pineconesundae在本站《spring》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 为什么不会呢?该 bean 由 Spring Boot 提供,并且只有在未手动提供任何内容时才会有条件地提供。这就是条件 bean 的全部意义所在。

  • 我一直在遵循本教程:https://www.baeldung.com/spring-boot-keycloak 使用 Keycloak 设置我的 Spring 应用程序。身份验证工作正常,但当我想添加基于角色的

    我一直在遵循本教程: https://www.baeldung.com/spring-boot-keycloak 使用 Keycloak 设置我的 Spring 应用程序。身份验证工作正常,但当我想添加基于角色的身份验证时,例如

    .requestMatchers(new AntPathRequestMatcher("/api/v1/user/**")).hasRole("user")
    

    我总是收到以下错误

    Bearer error="insufficient_scope", error_description="The request requires higher privileges than provided by the access token.", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"
    

    我已经使用以下方式检查了当局

    SecurityContextHolder.getContext().getAuthentication().getAuthorities();
    

    并且它只有带有前缀的。我 SCOPE_ 还检查了令牌并且它正确返回了它

     "realm_access": {
        "roles": [
          "offline_access",
          "uma_authorization",
          "default-master-realm",
          "user"
        ]
      },
    

    除了其他领域之外。

    这是我的 KeycloakConfig 课程:

    package com.motus.core.shared.config.security;
    
    import com.motus.auth.constants.Authority;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.Customizer;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
    import org.springframework.security.core.session.SessionRegistry;
    import org.springframework.security.core.session.SessionRegistryImpl;
    import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
    import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
    import org.springframework.security.web.SecurityFilterChain;
    import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
    import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
    import org.springframework.security.web.session.HttpSessionEventPublisher;
    import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
    
    import java.util.Collection;
    import java.util.HashSet;
    import java.util.Map;
    import java.util.Set;
    import java.util.stream.Collectors;
    
    @Slf4j
    @EnableWebSecurity
    @Configuration
    public class KeycloakConfig {
    
        private static final String GROUPS = "groups";
        private static final String REALM_ACCESS_CLAIM = "realm_access";
        private static final String ROLES_CLAIM = "roles";
    
        @Bean
        public SessionRegistry sessionRegistry() {
            return new SessionRegistryImpl();
        }
    
        @Bean
        protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
            return new RegisterSessionAuthenticationStrategy(sessionRegistry());
        }
    
        @Bean
        public HttpSessionEventPublisher httpSessionEventPublisher() {
            return new HttpSessionEventPublisher();
        }
    
        @Bean
        public SecurityFilterChain securityFilterChain(HttpSecurity http, KeycloakLogoutHandler keycloakLogoutHandler) throws Exception {
            http.authorizeHttpRequests(auth -> auth
                    .requestMatchers(new AntPathRequestMatcher("/api/v1/public/**")).permitAll()
                    .requestMatchers(new AntPathRequestMatcher("/api/v1/auth/**")).permitAll()
                    .requestMatchers(new AntPathRequestMatcher("/api/v1/admin/**")).hasRole("admin")
                    .requestMatchers(new AntPathRequestMatcher("/api/v1/user/**")).hasRole("user")
                    .anyRequest().authenticated()
            );
            http.oauth2ResourceServer(oauth2 -> oauth2
                    .jwt(Customizer.withDefaults()));
            http.oauth2Login(Customizer.withDefaults())
                    .logout(logout -> logout.addLogoutHandler(keycloakLogoutHandler).logoutSuccessUrl("/"));
    
            http.csrf(AbstractHttpConfigurer::disable);
            http.cors(Customizer.withDefaults());
    
            return http.build();
        }
    
        @Bean
        public GrantedAuthoritiesMapper userAuthoritiesMapperForKeycloak() {
            return authorities -> {
                Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
                var authority = authorities.iterator().next();
                boolean isOidc = authority instanceof OidcUserAuthority;
    
                if (isOidc) {
                    var oidcUserAuthority = (OidcUserAuthority) authority;
                    var userInfo = oidcUserAuthority.getUserInfo();
    
                    if (userInfo.hasClaim(REALM_ACCESS_CLAIM)) {
                        var realmAccess = userInfo.getClaimAsMap(REALM_ACCESS_CLAIM);
                        var roles = (Collection<String>) realmAccess.get(ROLES_CLAIM);
                        mappedAuthorities.addAll(generateAuthoritiesFromClaim(roles));
                    } else if (userInfo.hasClaim(GROUPS)) {
                        Collection<String> roles = userInfo.getClaim(
                                GROUPS);
                        mappedAuthorities.addAll(generateAuthoritiesFromClaim(roles));
                    }
                } else {
                    var oauth2UserAuthority = (OAuth2UserAuthority) authority;
                    Map<String, Object> userAttributes = oauth2UserAuthority.getAttributes();
    
                    if (userAttributes.containsKey(REALM_ACCESS_CLAIM)) {
                        Map<String, Object> realmAccess = (Map<String, Object>) userAttributes.get(
                                REALM_ACCESS_CLAIM);
                        Collection<String> roles = (Collection<String>) realmAccess.get(ROLES_CLAIM);
                        mappedAuthorities.addAll(generateAuthoritiesFromClaim(roles));
                    }
                }
                return mappedAuthorities;
            };
        }
    
        Collection<GrantedAuthority> generateAuthoritiesFromClaim(Collection<String> roles) {
            return roles.stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role)).collect(
                    Collectors.toList());
        }
    }
    

    看起来 GrantedAuthoritesMapper 没有被调用,您知道为什么吗?这是我在我的中添加的内容 pom.xml

    <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-oauth2-client</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
            </dependency>
    

    这是我在 application.properties 中添加的内容:

    spring.security.oauth2.client.registration.keycloak.client-id=${KEYCLOAK_CLIENT_ID:test-backend}
    spring.security.oauth2.client.registration.keycloak.authorization-grant-type=${KEYCLOAK_AUTHORIZATION_GRANT_TYPE:password}
    spring.security.oauth2.client.registration.keycloak.scope=${KEYCLOAK_SCOPE:openid}
    spring.security.oauth2.client.provider.keycloak.issuer-uri=${KEYCLOAK_ISSUER_URI:http://localhost:8080/realms/master}
    spring.security.oauth2.client.provider.keycloak.user-name-attribute=${KEYCLOAK_USER_NAME_ATTRIBUTE:username}
    spring.security.oauth2.resourceserver.jwt.issuer-uri=${KEYCLOAK_RESOURCE_SERVER_JWT_ISSUER_URI:http://localhost:8080/realms/master}
    

    我使用获取令牌, http://localhost:8080/realms/master/protocol/openid-connect/token 然后使用获取的令牌将请求发送到我的应用程序,但总是出现上述错误。有人知道我该如何解决这个问题吗?

  • hasRole('user') 需要 ROLE_user 权威

    任何一个:

    • 使用 hasAuthority('user')
    • 在将 Keycloak 角色映射到 Spring Security 权限时 ROLE_ 添加

    不要 oauth2ResourceServer 在同一个安全过滤器链中 oauth2Login 使用

    请记住,OAuth2 客户端使用资源服务器提供的资源(这些是不同的参与者)。在微服务架构中,经常会有应用程序同时扮演两种角色,但针对的是不同的资源(应使用不同的 Security(Web)FilterChain bean 进行保护)。

    Spring Boot 提供不同的启动器是有原因的。我知道 Baeldung 教程以及许多其他作者的教程,这些作者在不了解自己在做什么的情况下互相抄袭, oauth2ResourceServer 并且 oauth2Login 相同的安全过滤器链,但这毫无意义。让我们仔细看看这两个的安全配置:

    • oauth2ResourceServer 正在配置 OAuth2 资源服务器
      • authorizes requests based on a Bearer token in Authorization header
      • does not need sessions (can and should be stateless)
      • does not need protection against CSRF attacks (because it doesn't use sessions)
      • should return a 401 Unauthorized when the Authorization header is missing or invalid
      • maps authorities in a Converter<Jwt, ? extends AbstractAuthenticationToken> (if using JWT decoding, or customizing the introspector for opaque tokens)
    • oauth2Login 使用授权码流 配置

    这些要求差别太大,无法放在同一个 Security(Web)FilterChain bean 中。另外,请注意, authorities are not mapped the same way on oauth2ResourceServer with JWT decoder, oauth2ResourceServer with (opaque) token introspector, and OAuth2 clients with oauth2Login .

    附言

    您可能应该阅读 我的教程介绍 以了解更多 OAuth2 背景知识。

    附加启动器 可以 帮助您仅使用属性为 Keycloak 配置 Spring 应用程序(这些 Spring 应用程序主要是 OAuth2 客户端 oauth2Login 或 OAuth2 资源服务器)

返回
作者最近主题: