Oauth2-Resource-Server:请求的资源上不存在“ Access-Control-Allow-Origin”标头

时间:2019-01-22 11:05:31

标签: spring-boot angular6 spring-security-oauth2

我正在尝试使用Springboot(版本1.5.10.RELEASE)实现Oauth2.0安全性 我有一个包含以下模块的父项目

  • 家长应用
    • OAuth-Server-Module(在端口9999上运行)
    • 资源服务器模块(在端口9000上运行)
    • Web-Module(在端口8080上运行)
    • 通用模块

每个模块都是一个SpringBootApp。

我在Oauth2-Server-Module中有以下配置文件

    @Configuration
    public class AuthServerConfigAdapter extends WebMvcConfigurerAdapter {
        @Override
        public void addViewControllers(ViewControllerRegistry registry) {
            registry.addViewController("/login").setViewName("login");  
        }
    }
    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
        public class AuthServerSecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        private UserDetailsService userDetailsService;

        @Autowired
        DataSource dataSource;

        @Bean
        public BCryptPasswordEncoder bCryptPasswordEncoder() {
            return new BCryptPasswordEncoder();
        }

        @Autowired
        public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // @formatter:off

            http.formLogin().loginPage("/login").permitAll().and().requestMatchers()
                .antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access").and().authorizeRequests()
                .anyRequest().authenticated();

            // @formatter:on
        }
    }
@Configuration
@EnableAuthorizationServer
@Order(2)
public class Oauth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {

    private static final Logger _log = LoggerFactory.getLogger(Oauth2AuthorizationConfig.class);

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Autowired
    DataSource dataSource;

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {

        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        // TODO: Change for production
        KeyPair keyPair = new KeyStoreKeyFactory(new ClassPathResource("keystore.jks"), "Prism@xic-dw".toCharArray())
                .getKeyPair("doctor-world");
        converter.setKeyPair(keyPair);
        return converter;
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {

        _log.info(" 3 --- Authorization Server Security is Configured!!!");
        security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");

    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

        _log.info(" 2 --- Clients to whom access is provided are configured here!!!");
        clients.jdbc(dataSource);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

        _log.info(" 1 --- Authorization Server Endpoints are configured here!!!");
        endpoints.tokenServices(defaultTokenServices());
        endpoints.authenticationManager(authenticationManager).accessTokenConverter(jwtAccessTokenConverter());
    }

    @Bean
    public JwtTokenStore tokenStore() {

        JwtTokenStore store = new JwtTokenStore(jwtAccessTokenConverter());
        return store;
    }

    @Bean
    public TokenEnhancerChain tokenEnhancerChain() {

        final TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(new MyTokenEnhancer(), jwtAccessTokenConverter()));
        return tokenEnhancerChain;
    }

    @Bean
    public DefaultTokenServices defaultTokenServices() {
        final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setClientDetailsService(clientDetailsService);
        defaultTokenServices.setTokenEnhancer(tokenEnhancerChain());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }

    private static class MyTokenEnhancer implements TokenEnhancer {
        @Override
        public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
            if (authentication.getPrincipal() instanceof User) {
                final User user = (User) authentication.getPrincipal();
                final Map<String, Object> additionalInfo = new HashMap<>();
                additionalInfo.put(DWConstants.USER_ID, user.getId());
                ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
            }
            return accessToken;
        }
    }

}
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCorsFilter implements Filter {

    public static final Logger _log = LoggerFactory.getLogger(SimpleCorsFilter.class);

    public SimpleCorsFilter() {
        _log.info("SimpleCORSFilter init");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
        response.setHeader("Cache-Control", "no-store");

        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void destroy() {
    }
}
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Transactional(readOnly = true)
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        User user = userRepository.findByUsername(username);

        Set<GrantedAuthority> grantedAuthorities = new HashSet<GrantedAuthority>();
        for (Role role : user.getRoles()) {
            grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));
        }

        user.setAuthorities(grantedAuthorities);
        return user;
    }
}

我在Resource-Server-Module中也有以下配置文件

@SpringBootApplication
@EnableResourceServer
public class ResourceServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ResourceServerApplication.class, args);
    }
}
@Configuration
public class AuthResourceSecurityConfig extends ResourceServerConfigurerAdapter {

    @Value("${public.url.roles}")
    private String[] publicUrlroles;

    @Value("${user.url.roles}")
    private String[] userUrlroles;

    @Override
    public void configure(HttpSecurity http) throws Exception {

        http
//          .csrf().disable()
            .authorizeRequests()
            .antMatchers(publicUrlroles).permitAll()
            .antMatchers(userUrlroles).hasAnyRole("USER","ADMIN")
            .antMatchers("/v2/api-docs", "/configuration/**", "/swagger-resources/**",  "/swagger-ui.html", "/webjars/**", "/api-docs/**")
                .permitAll().anyRequest().denyAll().and().csrf().disable();
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("myResource");
    }
}
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsBypassFilter implements Filter {

    public CorsBypassFilter() {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
        response.setHeader("Cache-Control", "no-store");

        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void destroy() {
    }
}
@Component
public class RequestEnricherFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        if (SecurityContextHolder.getContext().getAuthentication()
                .getDetails() instanceof OAuth2AuthenticationDetails) {
            String accessToken = ((OAuth2AuthenticationDetails) SecurityContextHolder.getContext().getAuthentication()
                    .getDetails()).getTokenValue();
            Jwt decodedTokenJwt = JwtHelper.decode(accessToken);
            try {
                JSONObject jwtJSONOBject = new JSONObject(decodedTokenJwt.getClaims());
                if (!jwtJSONOBject.isNull("userId")) {
                    servletRequest.setAttribute("userId",
                            Long.parseLong(jwtJSONOBject.get("userId").toString()));
                    servletRequest.setAttribute("user_name",
                            jwtJSONOBject.get("user_name").toString());

                }
            } catch (JSONException e) {
                // TODO: add logger
                e.printStackTrace();
            }
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {

    }

    @Override
    public void destroy() { }
}
资源服务器模块的

application.properties文件

#Database Configuration

#Used By anyone - without Login 
public.url.roles=/v1/public/greetings

#Used By registered User in our system (By Admin Or User)
user.url.roles=/v1/user/user-detail/{userId}


#Below is the public key used to verify the jwt Signature which is coming in request. Replace it with Production public key
security.oauth2.resource.jwt.keyValue: -----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhYL3dk8NGj7d+H6YTFS35DiH6SyQJoeWvepSo+Nwwz/TBkKP0q2wNmDoYfzTy1enZpZNbdLpBxyPbvckjeHn+UAQutsSTmdMlf9itYSjGCzwwYAjgdk8ouJfodI3RhOx76Wz7VwO16pSTr2cRLSD2rFWPlRGS+v2fr+Q0PeEwOxQaeva54wFxLfQp/Os6T4AaD/F88YXO3VFb9fjLbQJWf+wD9DaDoiAcvT3ngxEGzY73DoH+VuoCoMnQlI2XbUI4hR91Hs6ePqbr2DDW5Th/Wzk33ZcGdHXyIfZDbSzfAFuOhpo4i03knzEtaAHuvAi5OPmpYSsrhQyrCUpYoLLqwIDAQAB\n-----END PUBLIC KEY-----

Web模块:

Oauth-server-module & Resource-server-Module Dependencies are included in pom.xml of web-module :

</dependencies>
    <dependency>
            <groupId>com.poc</groupId>
        <artifactId>authserver</artifactId>
    </dependency>
    <dependency>
        <groupId>com.poc</groupId>
        <artifactId>resource-server</artifactId>
    </dependency>
</dependencies>
@SpringBootApplication
@CrossOrigin(origins = { "http://my-domain.com", "http://localhost:4200" })
public class WebApplication {

    public static void main(String[] args) {
        SpringApplication.run(WebApplication .class, args);
    }
}
Web模块的

application.properties文件

#Database Configuration

#Used By anyone - without Login 
public.url.roles=/v1/public/greetings

#Used By registered User in our system (By Admin Or User)
user.url.roles=/v1/user/user-detail/{userId}


#Below is the public key used to verify the jwt Signature which is coming in request. Replace it with Production public key
security.oauth2.resource.jwt.keyValue: -----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhYL3dk8NGj7d+H6YTFS35DiH6SyQJoeWvepSo+Nwwz/TBkKP0q2wNmDoYfzTy1enZpZNbdLpBxyPbvckjeHn+UAQutsSTmdMlf9itYSjGCzwwYAjgdk8ouJfodI3RhOx76Wz7VwO16pSTr2cRLSD2rFWPlRGS+v2fr+Q0PeEwOxQaeva54wFxLfQp/Os6T4AaD/F88YXO3VFb9fjLbQJWf+wD9DaDoiAcvT3ngxEGzY73DoH+VuoCoMnQlI2XbUI4hR91Hs6ePqbr2DDW5Th/Wzk33ZcGdHXyIfZDbSzfAFuOhpo4i03knzEtaAHuvAi5OPmpYSsrhQyrCUpYoLLqwIDAQAB\n-----END PUBLIC KEY-----

当我尝试使用邮递员测试我的其余API时,它将在我的本地计算机上正常工作。

示例:我可以使用邮递员通过http://localhost:9999/oauth/token?grant_type=password&username=user&password=password

获取access_token

在通过access_token后,还使用http://localhost:8080/v1/public/greetingshttp://localhost:8080/v1/user/user-detail/ {userId}获取所有数据

现在,我为每个模块创建一个三个.jar文件,并在专用服务器上运行该文件,并尝试使用http://xxx.xxx.xx.xx:9999/oauth/token?grant_type=password&username=user&password=password获得一个access_token,然后它可以正常工作

但是当我尝试使用http://xxx.xxx.xx.xx:8080/v1/public/greetings获取数据时,它将显示错误401-未经授权

Error : Access to XMLHttpRequest at 'xxx.xxx.xx.xx::8080/v1/public/greetings' from origin 'mydomain.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

先谢谢您

0 个答案:

没有答案