Spring boot Oauth2 + Angular CORS问题

Posted

技术标签:

【中文标题】Spring boot Oauth2 + Angular CORS问题【英文标题】:Spring boot Oauth2 + Angular CORS problem 【发布时间】:2020-09-08 00:29:02 【问题描述】:

我是提供身份验证服务的新手。当我尝试从 Postman 获取访问令牌时,一切正常。但是当我使用 Angular 时,我得到了这个错误:

Access to XMLHttpRequest at 'localhost:8082/oauth/token' from origin 'http://localhost:4200' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.

我的配置是:

@SpringBootApplication
@EnableEurekaClient
@EnableWebSecurity
public class AuthMsApplication extends WebSecurityConfigurerAdapter 

public static void main(String[] args) 
    SpringApplication.run(AuthMsApplication.class, args);
 


@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
@WebFilter("/*")
public class CorsFilter implements Filter 

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException 
        final HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Allow-Headers", "content-type, x-requested-with, authorization");
        response.setHeader("Access-Control-Max-Age", "3600");
        if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) req).getMethod())) 
            response.setStatus(HttpServletResponse.SC_OK);
         else 
            chain.doFilter(req, res);
        
    


    @EnableAuthorizationServer
    @Configuration
    public class OAuth2Config extends AuthorizationServerConfigurerAdapter 

        private static final String READ = "read";
        private static final String WRITE = "write";
        private static final String PASSWORD = "password";
        private static final String REFRESH_TOKEN = "refresh_token";

        @Value("$client.id")
        private String clientId;
        @Value("$client.secret")
        private String clientSecret;
        @Value("$tokenSignature")
        private String tokenSignature;
        @Value("$accessTokenValiditySeconds")
        private int accessTokenValiditySeconds;
        @Value("$refreshTokenValiditySeconds")
        private int refreshTokenValiditySeconds;

        private final AuthenticationManager authenticationManager;
        private final UserDetailsService customDetailsService;

        public OAuth2Config(@Qualifier("authenticationProviderImpl") AuthenticationManager authenticationManager,
                            UserDetailsService customDetailsService) 
            this.authenticationManager = authenticationManager;
            this.customDetailsService = customDetailsService;
        

        @Bean
        public JwtAccessTokenConverter tokenEnhancer() 
            JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
            converter.setSigningKey(tokenSignature);
            return converter;
        

        @Bean
        public JwtTokenStore tokenStore() 
            return new JwtTokenStore(tokenEnhancer());
        

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) 
            endpoints.authenticationManager(authenticationManager)
                    .tokenStore(tokenStore())
                    .accessTokenConverter(tokenEnhancer())
                    .userDetailsService(customDetailsService);
        

        @Bean
        public PasswordEncoder encoder() 
            return new BCryptPasswordEncoder();
        

        @Override
        public void configure(AuthorizationServerSecurityConfigurer security) 
            security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");

        

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception 
            String encodedClientSecret = encoder().encode(clientSecret);
            clients.inMemory()
                    .withClient(clientId)
                    .secret(encodedClientSecret)
                    .scopes(READ, WRITE)
                    .authorizedGrantTypes(PASSWORD, REFRESH_TOKEN)
                    .accessTokenValiditySeconds(accessTokenValiditySeconds)
                    .refreshTokenValiditySeconds(refreshTokenValiditySeconds);
        
    

任何搜索信息都不能作为全局 CORS。一件事正在发挥作用

@CrossOrigin(origins = "*", allowedHeaders = "*")

但是我可以把它放在我自己的控制器上,我不知道如何为 oauth/token 端点设置它。

这个官方文档解决方案不起作用。 https://docs.spring.io/spring-security/site/docs/4.2.x/reference/html/cors.html

过滤器也不起作用。

【问题讨论】:

【参考方案1】:

3 天后,我找到了解决方案。首先,我删除了身份验证服务中的所有过滤器。其次,我在我的网关服务中添加了这个道具:

cloud:
gateway:
  globalcors:
    corsConfigurations:
      '[/**]':
        allowedOrigins: "*"
        allowedHeaders:
          - content-type
          - x-requested-with
          - Authorization
        allowedMethods:
          - GET
          - POST
          - OPTIONS
          - DELETE
          - PUT

您只需在网关道具中为您的所有服务添加全局标头,这也可以与服务中的过滤器相结合以获得更灵活的设置。 我希望这可以帮助一些人节省 3 天)

【讨论】:

这与doFilter() 中的做法有何不同?我和你有同样的问题,但我的 Java 应用程序中没有任何网关配置。【参考方案2】:

这是一个普遍的问题, 因为来源不同所以保护不同来源的注入。

解决方案:

1) 如果您使用的是 for dev,则在 chrome 上启用 CORS(扩展)(POSTMAN 默认执行此操作)

2) 在生产中,托管它的 Angular 应用程序应将您的 API URL 列入白名单,

3) 第三组 cors 允许原始标头

【讨论】:

以上是关于Spring boot Oauth2 + Angular CORS问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 spring-boot OAuth2 服务器保护的 Spring-boot 应用程序

让 oauth2 与 spring-boot 和 rest 一起工作

Spring Boot Restful WebAPI集成 OAuth2

Spring Boot + Spring Security + Spring OAuth2 + Google 登录

Spring Security +Oauth2 +Spring boot 动态定义权限

使用Spring boot的OAuth2认证服务器和资源服务器