org.springframework.security.access.AccessDeniedException: доступ запрещен - PullRequest
0 голосов
/ 24 февраля 2020

Я пытаюсь реализовать OAuth на моем сервере весенней загрузки. Вот мои настройки

configuration \ AuthorizationServerConfig. java

package com.vcomm.server.configuration;

import com.vcomm.server.service.util.CustomAuthenticationKeyGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.event.EventListener;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.annotation.Resource;
import javax.sql.DataSource;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

  @Resource(name = "roomUserDetailsService")
  UserDetailsService userDetailsService;

  @Autowired
  private DataSource dataSource;

  @Bean
  public TokenStore tokenStore() {
    JdbcTokenStore tokenStore = new JdbcTokenStore(dataSource);
    tokenStore.setAuthenticationKeyGenerator(new CustomAuthenticationKeyGenerator());
    return tokenStore;
  }

  @Bean
  public JwtAccessTokenConverter accessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setSigningKey("123");
    return converter;
  }

  @Bean
  @Primary
  public DefaultTokenServices tokenServices() {
    DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
    defaultTokenServices.setTokenStore(tokenStore());
    defaultTokenServices.setSupportRefreshToken(true);
    defaultTokenServices.setAuthenticationManager(authenticationManager);
    return defaultTokenServices;
  }

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

  @Autowired
  private AuthenticationManager authenticationManager;

  @Override
  public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
    endpoints
      .pathMapping("/oauth/authorize", Constant.AUTH_V1 + "/oauth/authorize")
      .pathMapping("/oauth/check_token", Constant.AUTH_V1 + "/oauth/check_token")
      .pathMapping("/oauth/confirm_access", Constant.AUTH_V1 + "/auth/v1/oauth/confirm_access")
      .pathMapping("/oauth/error", Constant.AUTH_V1 + "/oauth/error")
      .pathMapping("/oauth/token", Constant.AUTH_V1 + "/oauth/token")
      .pathMapping("/oauth/token_key", Constant.AUTH_V1 + "/oauth/token_key")
      .tokenStore(tokenStore())
      .userDetailsService(userDetailsService)
      .authenticationManager(authenticationManager);
  }

  @EventListener
  public void authSuccessEventListener(AuthenticationSuccessEvent authorizedEvent){
    // write custom code here for login success audit
    System.out.println("User Oauth2 login success");
    System.out.println("This is success event : "+authorizedEvent.getSource());
  }

  @Override
  public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
    oauthServer
      .tokenKeyAccess("permitAll()")
      .checkTokenAccess("isAuthenticated()");
    oauthServer.allowFormAuthenticationForClients();
  }
}

configuration \ ResourceServerConfig. java

package com.vcomm.server.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

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

    http
      .antMatcher("/api/**")
      .authorizeRequests()
      .anyRequest()
      .authenticated()
      .and()
      .exceptionHandling()
      .accessDeniedHandler(new OAuth2AccessDeniedHandler());
  }

  @Autowired
  TokenStore tokenStore;

  @Override
  public void configure(ResourceServerSecurityConfigurer config) {
    config.tokenServices(tokenServicesResourceServer());
  }

  @Autowired
  private AuthenticationManager authenticationManager;

  @Bean
  public DefaultTokenServices tokenServicesResourceServer() {
    DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
    defaultTokenServices.setTokenStore(tokenStore);
    defaultTokenServices.setAuthenticationManager(authenticationManager);
    return defaultTokenServices;
  }

}

configuration \ SpringWebSecurityConfig . java

package com.vcomm.server.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringWebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Configuration
  @Order(1001)
  public static class superAdminWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource(name = "emUserDetailsService")
    UserDetailsService emUserDetailsService;

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

      http
              .sessionManagement()
              .maximumSessions(2)
              .maxSessionsPreventsLogin(true);

      http
              .csrf().disable();
      http
              .httpBasic()
              .disable();

      http
              .authorizeRequests()
              .antMatchers("/superadmin/api/v1/login")
              .permitAll();

      http
              .logout()
              .logoutRequestMatcher(new AntPathRequestMatcher("/superadmin/api/v1/logout", "POST"))
              .deleteCookies("JSESSIONID")
              .logoutSuccessHandler((httpServletRequest, httpServletResponse, authentication) -> httpServletResponse.setStatus(HttpServletResponse.SC_NO_CONTENT))
              .invalidateHttpSession(true);

      http
              .antMatcher("/superadmin/**")
              .authorizeRequests()
              .antMatchers("/superadmin/**").hasAuthority("ADMIN_PRIVILEGE");

    }

    @Bean
    public PasswordEncoder passwordEncoder(){
      return new BCryptPasswordEncoder();
    }

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

    @Bean(name = "emAuthenticationProvider")
    public AuthenticationProvider emAuthenticationProvider() {
      DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
      provider.setPasswordEncoder(passwordEncoder());
      provider.setUserDetailsService(emUserDetailsService);
      return provider;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
      auth.userDetailsService(emUserDetailsService);
      auth.authenticationProvider(emAuthenticationProvider());
    }

  }

  @Configuration
  @Order(1002)
  public static class adminWebSecurityConfig extends WebSecurityConfigurerAdapter {

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

      http
              .sessionManagement()
              .maximumSessions(2)
              .maxSessionsPreventsLogin(true);

      http
              .csrf().disable();
      http
              .httpBasic()
              .disable();

      http
              .authorizeRequests()
              .antMatchers("/admin/api/v1/login")
              .permitAll();

      http
              .logout()
              .logoutRequestMatcher(new AntPathRequestMatcher("/admin/api/v1/logout", "POST"))
              .deleteCookies("JSESSIONID")
              .logoutSuccessHandler((httpServletRequest, httpServletResponse, authentication) -> httpServletResponse.setStatus(HttpServletResponse.SC_NO_CONTENT))
              .invalidateHttpSession(true);

      http
              .antMatcher("/admin/**")
              .authorizeRequests()
              .antMatchers("/admin/**").hasAuthority("ORGANISATION_PRIVILEGE");
    }


  }

  @Configuration
  @Order(1003)
  public static class appWebSecurityConfig extends WebSecurityConfigurerAdapter{

    @Resource(name = "roomUserDetailsService")
    UserDetailsService roomUserDetailsService;

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

      http
              .sessionManagement()
              .maximumSessions(2)
              .maxSessionsPreventsLogin(true);

      http
              .csrf().disable();
      http
              .httpBasic()
              .disable();

      http
              .authorizeRequests()
              .antMatchers("/api/v1/*/login")
              .permitAll();

      http
              .logout()
              .logoutRequestMatcher(new AntPathRequestMatcher("/api/v1/logout", "POST"))
              .deleteCookies("JSESSIONID")
              .logoutSuccessHandler((httpServletRequest, httpServletResponse, authentication) -> httpServletResponse.setStatus(HttpServletResponse.SC_NO_CONTENT))
              .invalidateHttpSession(true);

      http
              .antMatcher("/api/**")
              .authorizeRequests()
              .antMatchers("/api/**").hasAuthority("ROOM_PRIVILEGE");
    }

    @Bean(name = "roomPasswordEncoder")
    public PasswordEncoder roomPasswordEncoder(){
      return new BCryptPasswordEncoder();
    }

    @Override
    @Bean(name = "roomAuthenticationManager")
    public AuthenticationManager authenticationManager() throws Exception {
      return super.authenticationManagerBean();
    }

    @Bean(name = "roomAuthenticationProvider")
    public AuthenticationProvider roomAuthenticationProvider() {
      DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
      provider.setPasswordEncoder(roomPasswordEncoder());
      provider.setUserDetailsService(roomUserDetailsService);
      return provider;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
      auth.userDetailsService(roomUserDetailsService);
      auth.authenticationProvider(roomAuthenticationProvider());
    }

  }

}

При звонке http://localhost:5524/auth/v1/oauth/authorize?client_id=clientapp&response_type=code&scope=read я получил этот ответ

{
    "timestamp": 1582545217836,
    "status": 401,
    "error": "Unauthorized",
    "message": "Unauthorized",
    "path": "/auth/v1/oauth/authorize"
}

Я использую jdb c для управления состоянием oauth вот мои данные таблицы oauth

+-----------+--------------+---------------+-------+-------------------------------------------+-------------------------+-------------+-----------------------+------------------------+
| client_id | resource_ids | client_secret | scope | authorized_grant_types                    | web_server_redirect_uri | authorities | access_token_validity | refresh_token_validity |
+-----------+--------------+---------------+-------+-------------------------------------------+-------------------------+-------------+-----------------------+------------------------+
| clientapp | NULL         | secret        | read  | password,authorization_code,refresh_token | http://localhost:8081/  | room        |                 36000 |                  36000 |
+-----------+--------------+---------------+-------+-------------------------------------------+-------------------------+-------------+-----------------------+------------------------+

Я думаю этого журнала ошибок достаточно, чтобы ответить на этот вопрос, потому что я новичок в весенней загрузке. Если вам нужна дополнительная информация, пожалуйста, обращайтесь через коммент

1 Ответ

0 голосов
/ 26 февраля 2020

Это было мое недопонимание рабочего процесса OAuth. При вызове этого URL он пытается аутентифицировать меня перед предоставлением. Но почтальон показал только 401 вместо того, чтобы дать ответ перенаправления. Вызов через браузер перенаправит меня на страницу входа для аутентификации. Размещение этого ответа, чтобы помочь новичкам в OAuth и весенней загрузке:)

...