Невозможно получить доступ к ресурсам с помощью access_token: весенняя загрузка Oauth2 - PullRequest
0 голосов
/ 29 ноября 2018

Я пытаюсь реализовать Oauth2 в моем существующем приложении. Сначала я добавил Spring Security, а затем попытался добавить oauth2. После добавления конфигурации я могу сгенерировать access_token, но с помощью access_token я не могу получить доступ к ресурсам.

Вот мой код:

SecurityConfiguration.java

    @Configuration
    @EnableWebSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**");
    }

    @Autowired
    public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/", "/patients").permitAll()
                .antMatchers("/oauth/token").permitAll()
                .anyRequest().authenticated()
                .and().httpBasic();
        http.csrf().disable();
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource)
                .usersByUsernameQuery("select username, password, 1 as enabled from user where username=?")
                .authoritiesByUsernameQuery("select username, authority from authorities where username=?");
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public JdbcTokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

    @Bean
    @Autowired
    public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore) {
        TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
        handler.setTokenStore(tokenStore);
        handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
        handler.setClientDetailsService(clientDetailsService);
        return handler;
    }

    @Bean
    @Autowired
    public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
        TokenApprovalStore store = new TokenApprovalStore();
        store.setTokenStore(tokenStore);
        return store;
    }
}

SecurityOAuth2Configuration.java

@Configuration
@EnableAuthorizationServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Import(SecurityConfiguration.class)
public class SecurityOAuth2Configuration extends AuthorizationServerConfigurerAdapter {
    private static String REALM = "CRM_REALM";
    private static final int ONE_DAY = 60 * 60 * 24;
    private static final int THIRTY_DAYS = 60 * 60 * 24 * 30;

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private UserApprovalHandler userApprovalHandler;

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.realm(REALM);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler)
                .authenticationManager(authenticationManager);
    }
}

ResourceServer.java

@Configuration
@EnableResourceServer
public class ResourceServer extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.anonymous().disable()
                .requestMatchers().antMatchers("/patients/**").and().authorizeRequests()
                .antMatchers("/patient/**").access("hasRole('USER')")
                .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
    }

}

Я использовал этот учебник для справки.

Я могу получить токен доступа с использованием базовых учетных данных аутентификации.

enter image description here

Но когда я использовал тот же токен доступа для получения ресурсов, он не работает.enter image description here

Я добавил все необходимые таблицы для oauth.Что-то я пропускаю?

Обновление:

Я удалил .and().httpBasic(); и добавил @Order (3) в WebsecurityConfigurerAdapter и обновил файл свойств с security.oauth2.resource.filter-order = 3

теперь получаю ошибку как { "timestamp": 1543500350487, "status": 403, "error": "Forbidden", "message": "Access Denied", "path": "/patient/1/" }

Обновление 2

вот моя схема пользователя и прав доступа:

пользователь +----------+-----------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+-----------------+------+-----+---------+----------------+ | id | int(6) unsigned | NO | PRI | NULL | auto_increment | | username | varchar(50) | NO | UNI | NULL | | | password | varchar(100) | NO | | NULL | | +----------+-----------------+------+-----+---------+----------------+

органы +-----------+-----------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+-----------------+------+-----+---------+----------------+ | id | int(6) unsigned | NO | PRI | NULL | auto_increment | | username | varchar(50) | NO | MUL | NULL | | | authority | varchar(50) | NO | | NULL | | +-----------+-----------------+------+-----+---------+----------------+

Ответы [ 4 ]

0 голосов
/ 05 декабря 2018

Во-первых, у вас есть два похожих метода, которые изменяют AuthenticationManagerBuilder

@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {

и

@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {

Есть ли причина, по которой они оба существуют?У меня нет этого в моей конфигурации.

Кроме того, ваш запрос может работать некорректно.Вы должны следовать некоторым рекомендациям о том, как настроить службу пользователя для обработки вызова loaduserbyusername и объекта auth с одним из них.Как примечание: у меня не настроен тот же AuthenticationManagerBuilder, что и у вас, У меня есть настроенный для использования службы userdetails, наряду с паролем Encoder , например, так.

    auth.userDetailsService(securityUserService)
        .passwordEncoder(passwordEncoders.userPasswordEncoder());

Если это не помогает, вот альтернативный способ настройки:

Измените класс, который расширяет WebSecurityConfigurerAdapter на , только для конечной точки токена.

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
    .authorizeRequests()
        .antMatchers("/api/oauth/**").permitAll()
        .and()
    .csrf()
        .disable();
}

Теперь у вас в ResourceServerConfigurerAdapter есть проблемы с настройками на сервере ресурсов.Обратите внимание, это будет работать, только если ваша конфигурация AuthenticationManagerBuilder правильно загружает роль.Как уже отмечалось, Spring имеет префикс ROLE_.Которые по какой-то причине вы извлекаете с помощью запроса, и они являются авторитетными.

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

    http.csrf().disable()
    .requestMatchers()
        .antMatchers("/api/**")
        .and()
    .authorizeRequests()
        .antMatchers("/api/**").access("hasRole('USER')")
        .and()
    .exceptionHandling()
    .accessDeniedHandler(new OAuth2AccessDeniedHandler());

}

В моем файле AuthServerConfig нет следующих аннотаций:

@EnableGlobalMethodSecurity(prePostEnabled = true)
@Import(SecurityConfiguration.class)

Iсконфигурируйте AuthorizationServerSecurityConfigurer иначе, чем учебник, которым вы следовали, у меня следующее:

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

    oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}

Мой ClientDetailsServiceConfigurer все еще находится в памяти, так что это также отличается.Мой AuthorizationServerEndpointsConfigurer тоже немного отличается, я только добавляю токен-магазин, цепочку энхансеров (не беспокойтесь об этом, это дополнительно) и authenticationManager

    endpoints
        .tokenStore(tokenStore())
        .tokenEnhancer(tokenEnhancerChain)
        .authenticationManager(authenticationManager);
0 голосов
/ 03 декабря 2018

Вы должны использовать hasRole непосредственно в своем antmatcher вместо строки внутри функции access().Это оценит hasRole правильно и правильно определит, что пользователь имеет доступ к запрошенному ресурсу.

Это приведет к следующему коду для ResourceServer.java:

@Configuration
@EnableResourceServer
public class ResourceServer extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.anonymous().disable()
                .requestMatchers().antMatchers("/patients/**").and().authorizeRequests()
                .antMatchers("/patient/**").hasRole('USER')
                .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
    }

}
0 голосов
/ 05 декабря 2018

Пожалуйста, измените код, как показано ниже в ResourceServer:

Посмотрите на эту строку:

http.anonymous().disable()
                .requestMatchers().antMatchers("/patients/**","/patient/**")

С "/ Patient / " **, не добавляется как часть сопоставления запросов, запрос фактически обрабатывается другими configuration

package project.configuration;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;


@Configuration
@EnableResourceServer
public class ResourceServer extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.anonymous().disable()
                .requestMatchers().antMatchers("/patients/**","/patient/**").and().
                authorizeRequests().antMatchers("*/patient/**").hasRole("USER")
                .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
    }

}
0 голосов
/ 29 ноября 2018

Я подозреваю, что проблема может заключаться в том, как вы сохраняете / загружаете роли.В весенней безопасности для ролей есть префикс по умолчанию: ROLE_.Таким образом, в вашей БД (хранилище) вам нужно сохранить их как ROLE_FOO, например, а затем вы можете использовать hasRole('FOO')

Я нашел ту же проблему здесь, и мой ответ, казалось, решил проблему: https://stackoverflow.com/a/43568599/4473822

Человек, который получил проблему, также имел 403 - Forbidden и сохранение ролей в БД правильно решило проблему.

Вы также можете изменить префикс по умолчанию, но я бы не рекомендовал его, еслиВы хотите немного возиться с весной.

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