Oauth2-Resource-Server: в запрошенном ресурсе отсутствует заголовок «Access-Control-Allow-Origin» - PullRequest
0 голосов
/ 22 января 2019

Я пытаюсь реализовать безопасность Oauth2.0 с помощью Springboot (версия 1.5.10.RELEASE). У меня есть родительский проект со следующими модулями

  • Родительское приложение
    • OAuth-Серверный модуль (работает на порту: 9999)
    • Ресурсный серверный модуль (работает на порту: 9000)
    • Веб-модуль (работает на порту: 8080)
    • Общий модуль

Каждый модуль является приложением SpringBoot.

У меня есть следующие файлы конфигурации в 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 Файл Resource-Server-Module

#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);
    }
}

application.properties Файл Web-модуля

#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 с помощью почтальона, тогда он будет нормально работать на моей локальной машине.

Example: я могу получить access_token, используя почтальон через http://localhost:9999/oauth/token?grant_type=password&username=user&password=password

Также получить все данные, используя http://localhost:8080/v1/public/greetings & http://localhost:8080/v1/user/user-detail/{userId} после передачи access_token

Теперь я создаю три .jar-файла для каждого модуля и запускаю его на своем выделенном сервере и пытаюсь получить access_token, используя http://xxx.xxx.xx.xx:9999/oauth/token?grant_type=password&username=user&password=password, тогда он работает нормально

Но когда я пытаюсьдля получения данных с помощью 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.

Заранее спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...