Статьи

Безопасный Spring REST API с использованием OAuth2 + MySQL

Освободи свою безопасность вперед

Давайте защитим наш Spring REST API с помощью OAuth2 и MySQL. Мы будем хранить учетные данные пользователя в базе данных MySQL, а учетные данные клиента будут храниться в базе данных в памяти. Каждый клиент имеет свой уникальный идентификатор клиента.

Чтобы обеспечить безопасность нашего REST API, нам нужно будет сделать следующее:

  • Настройте Spring Security и базу данных.

  • Настройте сервер авторизации и сервер ресурсов.

  • Получите токен доступа и токен обновления.

  • Получить защищенный ресурс (REST API) с помощью токена доступа.

Прежде чем мы начнем, давайте рассмотрим некоторые основные концепции, связанные с Spring Security OAuth2 .

Вам также может понравиться: Spring Security Authentication .

OAuth2 Роли

Владелец ресурса

Владелец ресурса — это человек (например, конечный пользователь) в приложении, которому принадлежит служба или политика безопасности.

Ресурсный сервер

Это сервер ресурсов, на котором размещен защищенный ресурс или служба.

Клиентское приложение

Клиентское приложение — это приложение, запрашивающее доступ к ресурсам, хранящимся на сервере ресурсов. Клиентское приложение также получает авторизацию от владельца ресурса.

Сервер авторизации

Сервер авторизации — это сервер, который авторизует клиентское приложение для доступа к ресурсам владельца ресурса.

заявка

Давайте начнем защищать наши конечные точки API REST .

Во-первых, нам нужно включить Spring Security, чтобы добавить функцию безопасности в приложение. Для настройки и включения Spring Security используется  @EnableWebSecurity аннотация.

Используя  @EnableGlobalMethodSecurity,  мы можем легко защитить наши методы с помощью конфигураций Java. Глобальная безопасность метод активации   @PreFilter@PostFilter ,  @PreAuthorize, и  @PostAuthorize  аннотаций , если мы хотим использовать их.

@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  @Autowired
  UserDetailsServiceImpl userDetailsService;
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) 
      .and().authorizeRequests().antMatchers("/oauth/token")
      .permitAll().anyRequest().authenticated();
  }
  @Bean
  public DaoAuthenticationProvider authenticationProvider() {
    DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
    provider.setPasswordEncoder( bCryptPasswordEncoder() );
    provider.setUserDetailsService(userDetailsService);
    return provider;
  }
  @Bean
  public BCryptPasswordEncoder bCryptPasswordEncoder() {
    return new BCryptPasswordEncoder();
  }
  @Override
  @Bean
  public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
  }
  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProvider());
  }
}

Примечание:

  • Здесь  WebSecurityConfigurerAdapter  используется для настройки реализации безопасности.

  •  Endpoint /OAuth/tpken используется для запроса токена (доступа или обновления).

  • Мы внедряем пользовательскую реализацию  UserDetailsService для извлечения пользовательских данных из базы данных.

  • Мы используем определенный  BCryptPasswordEncoder компонент для кодирования пароля.

Теперь нам нужно настроить сервер авторизации. @EnableAuhtorizationServer  Аннотаций позволяет сервер авторизации. AuthorizationServerConfigurerAdapter  реализует   AuthorizationServerConfigurer, который предоставляет все необходимые методы для настройки сервера авторизации. Он также содержит информацию о зарегистрированных клиентах и ​​возможном доступе к областям действия и типам предоставления.

@Configuration
@EnableAuthorizationServer
public class OAuthConfiguration extends AuthorizationServerConfigurerAdapter {
  @Autowired
  @Qualifier("authenticationManagerBean")
  private AuthenticationManager authenticationManager;
  @Autowired
  UserDetailsService userDetailsService;
  @Override
  public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
    oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
  }
  @Override
  public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.inMemory()
      .withClient("fooClientId").secret("secret")
      .authorizedGrantTypes("password", "authorization_code", "refresh_token").scopes("read","write")
      .autoApprove(true);
  }
  @Override
  public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager).accessTokenConverter(defaultAccessTokenConverter())
      .userDetailsService(userDetailsService);
  }
  @Bean
  public TokenStore tokenStore(){
    return new JwtTokenStore(defaultAccessTokenConverter());
  }
  @Bean
  public JwtAccessTokenConverter defaultAccessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setSigningKey("123");
    return converter;
  }
}

Примечания по вышеуказанной конфигурации:

  • Регистрирует клиента с идентификатором клиента ‘ fooClientId‘ и паролем ‘  secret‘, а также ролями и областью его применения.

  • Определяет авторизованные типы предоставления (пароль, код авторизации, refresh_token).

  • Определяет  JwtTokenStore для хранения токенов.

Далее нам нужно настроить сервер ресурсов. @EnableResourceServer  Аннотаций, применяется на серверах OAuth2 ресурсов, позволяет фильтра Spring Security , который проверяет подлинность запросов , используя входящий маркер OAuth2.

Класс  ResourceServerConfigurerAdapter реализует  ResourceServerConfigure,   предоставляя методы для настройки правил доступа и путей, которые защищены безопасностью OAuth2.

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
    private static final String RESOURCE_ID = "resource-server-rest-api";
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId(RESOURCE_ID);
    }
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/**").authorizeRequests().anyRequest().authenticated();
    }
}

Далее нам нужно обновить  application.properties настройку базы данных MySQL. Создайте  user_management схему в MySQL и добавьте пользовательскую таблицу для хранения учетных данных пользователя с ролями.

spring.datasource.url = jdbc:mysql://localhost:3306/user_management
spring.datasource.username = root
spring.datasource.password = root

# Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto = update

# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy

# Use spring.jpa.properties.* for Hibernate native properties (the prefix is
# stripped before adding them to the entity manager)

# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
server.port = 8080

Тестовое приложение

Чтобы получить доступ к любой защищенной конечной точке REST API, сначала нам нужно получить токен доступа. Чтобы получить токен доступа, нам нужно добавить заголовок авторизации с учетными данными клиента и добавить тело запроса с учетными данными пользователя в почтальоне.

После получения токена доступа и обновления токена мы можем получить доступ к любым защищенным конечным точкам REST API с помощью токена доступа. Когда токен доступа истек, токен обновления используется для получения нового токена доступа.

Я приложил некоторые ответы на запросы почтальонов

# getToken

Получить токен

# getUser

Получить пользователя

# Добавить пользователя

Добавить пользователя

Вы можете обратиться ко всему проекту на  GitHub .

Статьи по Теме