← Назад к вопросам

Как понимаешь, что это твой токен

1.8 Middle🔥 201 комментариев
#Безопасность#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как понимаешь, что это твой токен

Этот вопрос касается аутентификации и управления токенами, что очень важно в современных веб-приложениях.

Способы валидации токена

1. Проверка подписи (самый надежный способ)

Для JWT токенов используется криптографическая подпись:

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureException;

@Service
public class JwtTokenValidator {
    
    private static final String SECRET_KEY = "your-secret-key-should-be-long-and-secure";
    
    /**
     * Проверяет, что токен подписан нашим приватным ключом
     * Если подпись не совпадает — выбросит исключение
     */
    public String validateAndGetUserId(String token) {
        try {
            // Парсим и валидируем подпись
            Claims claims = Jwts.parser()
                .setSigningKey(SECRET_KEY.getBytes())
                .parseClaimsJws(token)  // Проверяет подпись
                .getBody();
            
            // Если подпись валидна — можем доверять содержимому
            return claims.getSubject(); // user_id
        } catch (SignatureException e) {
            throw new InvalidTokenException("Token signature is invalid");
        }
    }
}

2. Проверка данных в токене

@Component
public class TokenValidator {
    
    /**
     * Проверяем, что токен содержит ожидаемые данные
     */
    public boolean isMyToken(String token, Long expectedUserId) {
        try {
            Claims claims = Jwts.parser()
                .setSigningKey(getSecret().getBytes())
                .parseClaimsJws(token)
                .getBody();
            
            // 1. Проверяем, что user_id совпадает
            Long tokenUserId = Long.valueOf(claims.getSubject());
            if (!tokenUserId.equals(expectedUserId)) {
                return false; // Это не твой токен!
            }
            
            // 2. Проверяем время истечения
            if (claims.getExpiration().before(new Date())) {
                return false; // Токен истек
            }
            
            // 3. Проверяем издателя (если есть)
            if (!"my-app".equals(claims.getIssuer())) {
                return false; // Токен от другого приложения
            }
            
            return true; // Это твой валидный токен!
            
        } catch (Exception e) {
            return false;
        }
    }
}

3. В контексте Spring Security

@Service
public class JwtAuthenticationService {
    
    @Autowired
    private JwtTokenProvider jwtTokenProvider;
    
    /**
     * Проверяем, что токен принадлежит текущему пользователю
     */
    public boolean isUserToken(String token, UserDetails userDetails) {
        try {
            // Парсим токен и проверяем подпись
            String username = jwtTokenProvider.getUsernameFromToken(token);
            
            // Проверяем, что username из токена совпадает с текущим пользователем
            return username.equals(userDetails.getUsername());
        } catch (Exception e) {
            return false;
        }
    }
}

4. Фильтр для валидации токена в запросе

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    
    @Autowired
    private JwtTokenValidator tokenValidator;
    
    @Autowired
    private UserRepository userRepository;
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, 
                                    HttpServletResponse response,
                                    FilterChain chain) throws ServletException, IOException {
        try {
            String token = extractTokenFromHeader(request);
            
            if (token != null) {
                // Проверяем, что это валидный токен нашего приложения
                String userId = tokenValidator.validateAndGetUserId(token);
                
                // Загружаем пользователя из БД
                User user = userRepository.findById(Long.valueOf(userId))
                    .orElseThrow(() -> new UserNotFoundException("User not found"));
                
                // Если всё OK — это точно твой токен
                // Создаем Authentication
                Authentication auth = new UsernamePasswordAuthenticationToken(
                    user, null, user.getAuthorities()
                );
                
                SecurityContextHolder.getContext().setAuthentication(auth);
            }
        } catch (InvalidTokenException e) {
            // Это не твой/невалидный токен
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }
        
        chain.doFilter(request, response);
    }
    
    private String extractTokenFromHeader(HttpServletRequest request) {
        String header = request.getHeader("Authorization");
        if (header != null && header.startsWith("Bearer ")) {
            return header.substring(7);
        }
        return null;
    }
}

5. Проверка в контроллере

@RestController
@RequestMapping("/api/v1/users")
public class UserController {
    
    @Autowired
    private JwtTokenValidator tokenValidator;
    
    /**
     * Получить профиль текущего пользователя
     * Токен был валидирован в фильтре
     */
    @GetMapping("/me")
    public UserResponse getCurrentUser(Authentication authentication) {
        // authentication уже содержит User из валидного токена
        User user = (User) authentication.getPrincipal();
        return new UserResponse(user);
    }
    
    /**
     * Проверить, что токен принадлежит конкретному пользователю
     */
    @GetMapping("/{userId}/verify-token")
    public ResponseEntity<Boolean> verifyUserToken(
            @PathVariable Long userId,
            @RequestHeader("Authorization") String authHeader) {
        try {
            String token = authHeader.substring(7);
            String tokenUserId = tokenValidator.validateAndGetUserId(token);
            
            boolean isMyToken = tokenUserId.equals(String.valueOf(userId));
            return ResponseEntity.ok(isMyToken);
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(false);
        }
    }
}

6. Хранение и использование токенов на клиенте

// Android / Java Client
public class TokenManager {
    private SharedPreferences preferences;
    
    /**
     * Сохраняем токен после логина
     */
    public void saveToken(String token) {
        preferences.edit()
            .putString("auth_token", token)
            .apply();
    }
    
    /**
     * Проверяем, что это наш токен (просто проверяем наличие)
     */
    public boolean hasMyToken() {
        String token = preferences.getString("auth_token", null);
        return token != null && !token.isEmpty();
    }
    
    /**
     * Удаляем токен при логауте
     */
    public void clearToken() {
        preferences.edit()
            .remove("auth_token")
            .apply();
    }
}

Ключевые моменты для понимания «твоего токена»:

1. Криптографическая подпись — если подпись валидна, токен от нас

2. Содержимое токена — user_id, username, роли всегда совпадают

3. Срок действия — проверяем, не истек ли токен

4. Издатель (issuer) — убеждаемся, что это наше приложение

5. В контексте пользователя — проверяем, что user_id из токена совпадает с ID запрашивающего пользователя

Аналогия из реальной жизни:

Токен — это как паспорт:

  • Подпись государства = криптографическая подпись приложения
  • ФИО в паспорте = user_id и username в токене
  • Дата истечения = expiration claim
  • Где выдан = issuer claim

Если всё совпадает — это точно твой паспорт! Без проверки подписи любой может поддельный выпустить.

Как понимаешь, что это твой токен | PrepBro