Cookieдахранится вклиент(браузер пользователя)изнебольшие фрагменты данных,Может использоваться для запоминания информации, связанной с пользователем.,Например, учетные данные для входа или настройки. Они отправляются на сервер с каждым HTTP-запросом.,и может быть прочитан сервером для поддержания сеанса или персонализации взаимодействия с пользователем.
Например: Представьте, что пользователь заходит на сайт банка. Сервер создает файл cookie, содержащий идентификатор сеанса, и отправляет его обратно в браузер пользователя через заголовок Set-Cookie. Браузер сохраняет этот файл cookie и отправляет его обратно на сервер при последующих запросах, позволяя серверу распознавать пользователя и поддерживать его вход в систему при нескольких загрузках страниц.
会话用于跟踪用户существовать多个页面请求期间из状态。它们通常хранится всерверная часть,и связан с уникальным идентификатором сеанса (обычно идентификатор сеанса),Идентификатор сеанса отправляется клиенту в виде файла cookie. Сессии позволяют серверу запоминать информацию о пользователе во время его посещения.
Например: Пользователи совершают покупки на сайтах электронной коммерции. Сервер создает сеанс для пользователя, сохраняя его товары в корзине покупок и другую соответствующую информацию. Идентификатор сеанса отправляется в браузер пользователя в виде файла cookie. Когда пользователь перемещается по сайту, идентификатор сеанса в файле cookie позволяет серверу получать доступ к данным сеанса пользователя, обеспечивая пользователю беспрепятственный процесс совершения покупок.
Tokendaa форма аутентификации статуса никто,клиентиметьжетон,Обычно даа строка,Используется для аутентификации запросов к серверу. Токен не требует, чтобы сервер отслеживал статус пользователя.,Потому что вся необходимая информация закодирована в самом жетоне.
Например: Пользователи хотят получить доступ к своей электронной почте через мобильные приложения. Приложение отправляет запрос с учетными данными пользователя на сервер провайдера электронной почты. После успешной аутентификации сервер выдает токен доступа. Приложение сохраняет этот токен и использует его в последующих запросах API для доступа к электронной почте пользователя.
JWTдаa компактный、Безопасный метод представления претензий между двумя сторонами. JWTда содержит заголовок、нагрузкаи签名изJSON-объект。JWTМожет использоваться для аутентификациииавторизованный пользователь,Они самостоятельны,Это означает, что вся информация, необходимая для их проверки, содержится в самом жетоне.
Например: Разработчик создает веб-приложение с функцией единого входа. После входа пользователя в систему сервер генерирует JWT, содержащий идентификатор и разрешения пользователя. Этот JWT отправляется клиенту и сохраняется локально. Когда пользователь хочет получить доступ к защищенному ресурсу, клиент включает JWT в заголовок авторизации HTTP-запроса. Сервер проверяет JWT и, если он действителен, предоставляет доступ к ресурсу.
Ниже приведена таблица, иллюстрирующая их различия в различных аспектах.
характеристика | Cookie | Session | Token | JWT |
---|---|---|---|---|
определение | Данные отправляются с сервера в браузер для отслеживания статуса. | Ведение журнала состояния сеанса на стороне сервера | Токен безопасности для аутентификации и обмена информацией | Облегченный механизм аутентификации на основе JSON |
место хранения | клиент | серверная часть | клиент(LocalStorageилиCookie) | клиент(LocalStorageилиCookie) |
безопасность | Низкий, легко быть украденным или подделанным | Выше данные не раскрываются в клиенте | Выше, особенно для криптотокенов | Высший, содержит подпись, проверяет целостность данных |
Междоменная поддержка | Не поддерживается по умолчанию, может быть достигнуто через настройки | Не поддерживается, зависит от файлов cookie | Поддержка, не полагается на файлы cookie | Поддержка, не полагается на файлы cookie |
ограничение размера | Около 4 КБ | никтоограничение размера | никтоограничение размера | Обычно меньше, но под влиянием ограничения размера JSON. |
жизненный цикл | Срок годности можно установить | Обычно срок действия истекает после закрытия пользователем браузера или истечения времени ожидания. | Срок годности можно установить | Срок годности можно установить |
Поддержка без гражданства | Не поддерживается, зависит от файлов cookie | Поддерживается, но сеанс должен основываться на файлах cookie. | Поддерживается, сервер без сохранения состояния | Поддерживается, сервер без сохранения состояния |
Применимые сценарии | Простое отслеживание сеансов, пользовательские настройки | Сценарии, требующие от сервера запоминания статуса пользователя | Мобильные приложения, аутентификация API, междоменные запросы | Веб-приложения, мобильные приложения, единый вход |
Междоменные проблемы | Есть междоменные ограничения | никто Междоменные проблемы, но необходимо обрабатывать совместное использование сеансов при развертывании кластера. | никто Междоменные проблемы, подходят для междоменной аутентификации | никто Междоменные проблемы, подходят для междоменной аутентификации |
Давление сервера | никто | Давление сервера будет увеличиваться при высоком уровне параллелизма | Низкий, подходит для крупномасштабного развертывания | Низкий, подходит для крупномасштабного развертывания |
тип данных | Поддерживает только строки | Может хранить данные любого типа | Может хранить данные любого типа | Может хранить неконфиденциальную информацию |
Ниже мы представляем различия между четырьмя из них, исходя из их преимуществ и недостатков.
механизм | Введение | преимущество | недостаток | Применимые сценарии |
---|---|---|---|---|
Cookie | Храните небольшие текстовые файлы в клиенте | Простой в использовании, поддерживает междоменный доступ. | Ограниченная емкость хранилища, уязвимая для атак CSRF. | Храните небольшие объемы неконфиденциальной информации, такой как пользовательские настройки и т. д. |
Session | Хранить данные, связанные с конкретным сеансом пользователя, на сервере. | безопасность выше и может хранить конфиденциальную информацию | Повышенная нагрузка на сервер и необходимость поддерживать состояние сеанса. | Хранит более конфиденциальную информацию, такую как статус входа пользователя, содержимое корзины покупок и т. д. |
Token | Токены, используемые для аутентификации и авторизации | никтостатус、Расширяемый、Междоменный домен | Необходимы дополнительные меры безопасности для защиты жетона и увеличения нагрузки на сеть передачи. | Аутентификация API, особенно в распределенных системах |
JWT | Открытый стандарт на основе JSON для безопасной передачи информации. | Расширяемый、автономный、никому требуется статус сервера | После издания никто закон не отменяется、Увеличение нагрузки на сеть передачи данных | Междоменная аутентификация, особенно в распределенных системах и сценариях единого входа (SSO). |
Резюме: файлы cookie и Session да Традиционный серверный механизм управления сессиями, при этом Token и JWT Тогда да — это более гибкий и безопасный механизм аутентификации и авторизации, подходящий для распределенных систем и сценариев приложений, в которых внешний и внутренний серверы разделены. JWT да Token из一种实现方式,具有更高из可移植секси Расширяемыйсекс。
Вот некоторые практические различия между да в Springboot
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Date;
@SpringBootApplication
@RestController
public class AuthApplication {
private final String SECRET_KEY = "secretkey123"; // Ключ шифрования JWT
public static void main(String[] args) {
SpringApplication.run(AuthApplication.class, args);
}
@GetMapping("/setCookie")
public String setCookie(HttpServletResponse response) {
Cookie cookie = new Cookie("user", "john_doe");
cookie.setMaxAge(3600); // 设置Cookieизжизненный цикл 1 час
response.addCookie(cookie);
return «Настройка файлов cookie прошла успешно!»;
}
@GetMapping("/setSession")
public String setSession(HttpServletRequest request) {
HttpSession session = request.getSession();
session.setAttribute("user", "john_doe");
return "Сессия успешно установлена!";
}
@GetMapping("/getCookie")
public String getCookie(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("user")) {
return «Получить информацию о пользователе из файлов cookie:» + cookie.getValue();
}
}
}
return «Куки не найден!»;
}
@GetMapping("/getSession")
public String getSession(HttpServletRequest request) {
HttpSession session = request.getSession();
String user = (String) session.getAttribute("user");
if (user != null) {
return «Получить информацию о пользователе из сеанса:» + user;
}
return «Сессия не найдена!»;
}
@PostMapping("/login")
public String login(@RequestBody UserCredentials credentials) {
// В практических приложениях пользователи должны проходить аутентификацию здесь, например, проверять совпадение имени пользователя и пароля в базе данных.
if (credentials.getUsername().equals("john_doe") && credentials.getPassword().equals("password123")) {
// Создать токен
String token = Jwts.builder()
.setSubject(credentials.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 3600000)) // Установите срок действия токена на 1 час.
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
return «Вход успешен! Сгенерирован токен:» + token;
} else {
return «Неверное имя пользователя или пароль!»;
}
}
@GetMapping("/secure")
public String secure(HttpServletRequest request) {
// В практических приложениях валидность токена должна быть проверена здесь.
String token = request.getHeader("Authorization").replace("Bearer ", "");
String user = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getSubject();
return «Доступ к защищенной конечной точке успешен, пользователь:» + user;
}
static class UserCredentials {
private String username;
private String password;
// Getters and setters
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
}
Я считаю, что прочитав этот код, вы уже должны понять самую основную разницу.
После этого я порекомендую некоторые из лучших практик реального боя (это не значит, что они лучшие, это лучшие в моем случае. Если есть какие-либо ошибки, вы можете обсудить их в области комментариев).
Сначала вам нужно добавить Spring SecurityиJWTиз依赖项到你изpom.xml
в файле:
<dependencies>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- JSON Web Token Support -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>
Затем вы можете создать служебный класс JWT для создания и проверки JWT:
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.function.Function;
@Component
public class JwtUtils {
private String secret = "yourSecretKey"; // твой ключ
public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 3600000)) // Срок действия истекает через 1 час
.signWith(SignatureAlgorithm.HS256, secret)
.compact();
}
public Boolean validateToken(String token, String username) {
final String usernameFromToken = getUsernameFromToken(token);
return (usernameFromToken.equals(username) && !isTokenExpired(token));
}
public String getUsernameFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}
private Claims getAllClaimsFromToken(String token) {
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
}
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
}
Затем создайте контроллер для обработки запроса на вход и сгенерируйте JWT:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtUtils jwtUtils;
@PostMapping("/signin")
public String signin(@RequestBody User user) throws AuthenticationException {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword())
);
return jwtUtils.generateToken(user.getUsername());
}
@GetMapping("/info")
public String info(@RequestParam String token) {
if (jwtUtils.validateToken(token, "user")) {
return "Token is valid!";
} else {
return "Token is not valid!";
}
}
}
Наконец, вам необходимо настроить Spring Security для использования JWT для аутентификации:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic(); // Используйте базовую аутентификацию
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user")
.password("password")
.roles("USER");
}
}
Это можно использовать только как план для собственного обучения.,Если проект да выйдет в интернет,Также необходимо учитывать множество вопросов безопасности.
Вот некоторые меры:
Для защиты данных, передаваемых между клиентскими серверами, безопасность,Вам следует использовать HTTPS. HTTPS шифрует данные через SSL/TLS,Предотвратите атаки типа «человек посередине» и утечку данных.
Весной Включить HTTPS при загрузке:
1.существоватьapplication.properties
илиapplication.yml
中配置服务器изSSL属секс
server.port=8443
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=yourpassword
server.ssl.key-password=yourkeypassword
2.Создать файл хранилища ключей(keystore.jks
)并配置适当из密码。
3. Убедитесь, что ваше приложение доступно через порт 8443, который является портом по умолчанию для HTTPS.
Для JWT, Управление ключамидом жизненно важно. Вам следует использовать безопасный способ хранения и доступа к ключу подписи.,И ключи меняйте регулярно.
Управление ключамилучшие практики:
Подделка межсайтовых запросов (CSRF) — это атака, при которой злоумышленник может использовать удостоверение пользователя, прошедшее проверку подлинности, для выполнения неожиданных операций без ведома пользователя.
Весной Предотвратить CSRF в безопасности:
@csrfProtection
аннотация для включенияCSRFЗащищать。_csrf
жетон。@PostMapping("/some-protected-action")
@csrfProtection
public String someProtectedAction(@ModelAttribute SomeData data, @RequestParam("csrfToken") String csrfToken) {
// твоя бизнес-логика
}