← Назад к вопросам
Как понимаешь, что это твой токен
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
Если всё совпадает — это точно твой паспорт! Без проверки подписи любой может поддельный выпустить.