OAuth 2.0 и JWT авторизация на Java: руководство для начинающих

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в OAuth 2.0 и JWT на Java

Современные веб-приложения и API требуют надежных механизмов аутентификации и авторизации. Два наиболее популярных стандарта в этой области — OAuth 2.0 и JWT (JSON Web Tokens). Если вы начинающий Java-разработчик, понимание этих технологий откроет вам путь к созданию безопасных и масштабируемых приложений.

В этой статье мы разберем, что такое OAuth 2.0 и JWT, как они работают вместе, и как реализовать их на Java с использованием популярных библиотек. Вы узнаете, как настроить сервер авторизации, генерировать и проверять JWT-токены, а также защитить свои REST API.

Что такое OAuth 2.0 и JWT?

OAuth 2.0 — протокол делегированного доступа

OAuth 2.0 — это протокол авторизации, который позволяет приложениям получать ограниченный доступ к ресурсам пользователя без передачи его учетных данных. Представьте, что вы хотите дать приложению доступ к вашим фотографиям в Google. Вместо того чтобы сообщать приложению свой пароль от Google, вы используете OAuth 2.0, который выдает приложению временный токен с ограниченными правами.

Основные участники OAuth 2.0:

  • Resource Owner — пользователь, владеющий ресурсами
  • Client — приложение, запрашивающее доступ
  • Authorization Server — сервер, выдающий токены
  • Resource Server — сервер, предоставляющий защищенные ресурсы

JWT — компактный формат токена

JWT (JSON Web Token) — это открытый стандарт (RFC 7519) для создания токенов доступа, которые содержат утверждения (claims) в формате JSON. JWT состоит из трех частей, разделенных точками:

  • Header — содержит тип токена и алгоритм подписи (например, HS256 или RS256)
  • Payload — содержит утверждения (например, ID пользователя, роли, срок действия)
  • Signature — подпись, которая гарантирует целостность токена

Пример JWT: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U

Реализация OAuth 2.0 и JWT на Java

Настройка проекта с Spring Security

Для реализации OAuth 2.0 и JWT на Java мы будем использовать Spring Boot и Spring Security. Начнем с добавления зависимостей в файл pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.12.3</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.12.3</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.12.3</version>
    <scope>runtime</scope>
</dependency>

Создание JWT-провайдера

Создадим класс JwtProvider, который будет отвечать за генерацию и валидацию JWT-токенов:

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.Date;

@Component
public class JwtProvider {
    private final SecretKey secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
    private final long expirationMs = 3600000; // 1 час

    public String generateToken(String username) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + expirationMs);

        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(now)
                .setExpiration(expiryDate)
                .signWith(secretKey)
                .compact();
    }

    public boolean validateToken(String token) {
        try {
            Jwts.parserBuilder()
                .setSigningKey(secretKey)
                .build()
                .parseClaimsJws(token);
            return true;
        } catch (JwtException | IllegalArgumentException e) {
            return false;
        }
    }

    public String getUsernameFromToken(String token) {
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(secretKey)
                .build()
                .parseClaimsJws(token)
                .getBody();
        return claims.getSubject();
    }
}

Реализация OAuth 2.0 Resource Server

Теперь создадим конфигурацию безопасности для защиты наших эндпоинтов:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeHttpRequests(authz -> authz
                .requestMatchers("/api/auth/**").permitAll()
                .requestMatchers("/api/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .addFilterBefore(jwtAuthenticationFilter(), 
                UsernamePasswordAuthenticationFilter.class);
        
        return http.build();
    }

    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter() {
        return new JwtAuthenticationFilter();
    }
}

Создание фильтра аутентификации

Фильтр будет перехватывать все запросы, извлекать JWT из заголовка и проверять его:

import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java                

Блоги

Рекомендаций по книгам