Spring OAuth2 SSO предварительная обработка запросов - PullRequest
0 голосов
/ 22 мая 2019

Я изучаю Spring OAuth и у меня возникли некоторые проблемы с CORS и предполётными запросами, возможно, кто-то может мне помочь.

В качестве основы я взял пример проекта из книги "Cloud Native Java": https://github.com/cloud-native-java/edge

Для моего вопроса важны две части: служба SSO шлюза (greetings-client) и служба авторизации (служба аутентификации).

Вот конфигурация SSO:

@Configuration
@EnableOAuth2Sso
class SsoConfiguration extends WebSecurityConfigurerAdapter {

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

    http.antMatcher("/**").authorizeRequests()
            .antMatchers( "/", "/app.js", "/login**", "/webjars/**").permitAll().anyRequest()
            .authenticated().and().logout().logoutSuccessUrl("/").permitAll().and().csrf()
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
    }
}

EdgeСервис имеет простую часть пользовательского интерфейса.При непосредственном вызове он пытается сделать запрос к / user конечной точке, которая защищена, для получения информации о Принципале.

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <title>Edge Service</title>
    <meta name="description" content=""/>
    <meta name="viewport" content="width=device-width"/>
    <base href="/"/>
    <script type="text/javascript"
            src="/webjars/jquery/jquery.min.js"></script>
    <script type="text/javascript"
            src="/webjars/bootstrap/js/bootstrap.min.js"></script>
    <script type="text/javascript"
            src="/webjars/angularjs/angular.min.js"></script>
</head>

<body ng-app="app" ng-controller="home as home">

<div class="container" ng-show="!home.authenticated">
    <a href="/login">Login </a>
</div>

<div class="container" ng-show="home.authenticated">

    <!--1-->
    Logged in as:
    <b><span ng-bind="home.user"></span></b> <br/>

    Token:
    <b><span ng-bind="home.token"></span> </b><br/>

    Greeting from Zuul Route: <b>
    <span ng-bind="home.greetingFromZuulRoute"></span></b> <br/>

    Greeting from Edge Service (Feign):
    <b><span ng-bind="home.greetingFromEdgeService"></span></b><br/>
</div>

<!--2-->
<script type="text/javascript" src="app.js"></script>
</body>
</html>

И javascript:

var app = angular.module("app", []);

//<1>
app.factory('oauth', function () {
    return {details: null, name: null, token: null};
});

app.run(['$http', '$rootScope', 'oauth', function ($http, $rootScope, oauth) {

    $http.get("/user").success(function (data) {

        oauth.details = data.userAuthentication.details;
        oauth.name = oauth.details.name;
        oauth.token = data.details.tokenValue;

        // <2>
        $http.defaults.headers.common['Authorization'] = 'bearer ' + oauth.token;

        // <3>
        $rootScope.$broadcast('auth-event', oauth.token);
    });
}]);

app.controller("home", function ($http, $rootScope, oauth) {

    var self = this;

    self.authenticated = false;

    // <4>
    $rootScope.$on('auth-event', function (evt, ctx) {
        self.user = oauth.details.name;
        self.token = oauth.token;
        self.authenticated = true;

        var name = window.prompt('who would you like to greet?');

        // <5>
        $http.get('/greetings-service/greet/' + name)
            .success(function (greetingData) {
                self.greetingFromZuulRoute = greetingData.greeting;
            })
            .error(function (e) {
                console.log('oops!' + JSON.stringify(e));
            });

        // <6>
        $http.get('/lets/greet/' + name)
            .success(function (greetingData) {
                self.greetingFromEdgeService = greetingData.greeting;
            })
            .error(function (e) {
                console.log('oops!' + JSON.stringify(e));
            });
    });
});

Таким образом, ожидается , что процедура входа в систему инициируется и появляется форма входа.

Фактический результат: браузер перенаправляется на сервер авторизации и вызывает ошибку CORS

Доступ к XMLHttpRequest в 'http://localhost:9191/uaa/oauth/authorize?client_id=html5&redirect_uri=http://localhost:8082/login&response_type=code&state=1zegi7' (перенаправлен из' http://localhost:8082/user') из источника 'http://localhost:8082' заблокирован политикой CORS: Ответ на запрос предполетной проверки не проходитпроверка контроля доступа: у него нет статуса HTTP ok.

Здесь: localhost: 8082 - служба шлюза, localhost: 9191 - сервер авторизации.

В консоли обозревателя я вижу, чтобыл запрос OPTIONS.

С другой стороны, если я явно вызываю конечную точку / login (предоставлена ​​Spring), она работает как положено - появляется форма входа в систему, и после проверки учетных данных меня перенаправляютобратно в домстр.

Служба шлюза имеет простой фильтр сервлетов, где я явно устанавливаю заголовок ACCESS_CONTROL_ALLOW_ORIGIN.

@Component
class CorsFilter implements Filter {

    private final Log log = LogFactory.getLog(getClass());

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = HttpServletResponse.class.cast(res);
        HttpServletRequest request = HttpServletRequest.class.cast(req);

        log.info(request.getMethod());

        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");

        chain.doFilter(req, res);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }

}

Вопросы:

  • Какправильно обрабатывать запросы предварительной проверки в таком случае?
  • Разве фильтр сервлета не должен обрабатывать запрос OPTIONS?(Я не вижу в логах)

Что я пробовал:

  • Использовать явный фильтр сервлетов (показан выше)
  • Используйте метод HttpSecurity.cors () в сочетании с компонентом CorsConfigurationSource:

    @Configuration
    @EnableOAuth2Sso
    class SsoConfiguration extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    
        http.cors().and().antMatcher("/**").authorizeRequests()
                .antMatchers( "/", "/app.js", "/login**", "/webjars/**").permitAll().anyRequest()
                .authenticated().and().logout().logoutSuccessUrl("/").permitAll().and().csrf()
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
    }
    
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedMethods(Arrays.asList("GET","POST","OPTIONS"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
    }
    

ОБНОВЛЕНИЕ: Вот свойства, которые я использовал для шлюза SSO:

spring.application.name=greetings-client
server.port=${PORT:8082}
security.oauth2.resource.userInfoUri=http://auth-service/uaa/user
spring.mvc.dispatch-options-request=true

zuul.routes.hi.path=/lets/**
zuul.routes.hi.serviceId=greetings-service

management.security.enabled=false

zuul.ignoredServices=*

eureka.instance.preferIpAddress=true
eureka.instance.leaseRenewalIntervalInSeconds=10

А вот свойства для службы аутентификации:

server.port=${PORT:9191}
spring.application.name=auth-service
server.context-path=/uaa
security.sessions=if_required
logging.level.org.springframework.security=DEBUG
spring.jpa.hibernate.ddl-auto=create
spring.jpa.generate-ddl=true

eureka.instance.preferIpAddress=true
eureka.instance.leaseRenewalIntervalInSeconds=10

и настройки сервера авторизации:

@Configuration
@EnableAuthorizationServer
class AuthorizationServerConfiguration extends
        AuthorizationServerConfigurerAdapter {

    private final AuthenticationManager authenticationManager;

    private final ClientDetailsService clientDetailsService;

    @Autowired
    public AuthorizationServerConfiguration(
            AuthenticationManager authenticationManager,
            ClientDetailsService clientDetailsService) {
        this.authenticationManager = authenticationManager;
        this.clientDetailsService = clientDetailsService;
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // <1>
        clients.withClientDetails(this.clientDetailsService);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints)
            throws Exception {
        // <2>
        endpoints.authenticationManager(this.authenticationManager);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...