Эта статья полностью понимает, что такое Cookie, Session и Token.

Java

Писательские навыки у автора пока неглубокие, если что не так, укажите великодушно, буду признателен

Cookie

 1洛:大爷,楼上322住的是马冬梅家吧?
2
3大爷:马都什么?
4
5夏洛:马冬梅。
6
7大爷:什么都没啊?
8
9夏洛:马冬梅啊。
10
11大爷:马什么没?
12
13夏洛:行,大爷你先凉快着吧。

Прежде чем понять эти три концепции, мы должны сначала понять, что HTTPнет статусавеб-сервер, что такое без гражданства? Как и в классической сцене диалога в «Раздражении Шарлотты» выше, один диалог завершается, а следующий совершенно не знает, что случилось с последним. Если он используется только для управления статическими файлами на веб-сервере, не имеет значения, кто является другой стороной, просто прочитайте файл с диска и отправьте его. Но с непрерывным развитием сети, например, корзина в электронной коммерции может выполнять следующую серию действий только после запоминания личности пользователя. Итак, нам нужнонет статусаСервер помнит несколько вещей.

Так как же веб-сервер что-то запоминает? Поскольку веб-сервер ничего не запоминает, мы пытаемся запоминать что-то извне, что эквивалентно тому, что сервер прикрепляет небольшую заметку к каждому клиенту. Приведенное выше записывает некоторую информацию, возвращаемую нам сервером. Затем сервер видит эту маленькую заметку и знает, кто мы. ТакCookieКто его произвел? Файлы cookie генерируются сервером. Далее мы описываемCookieПроцесс производит

  1. Когда браузер обращается к серверу в первый раз, сервер не должен знать его личность в это время, поэтому создайте уникальные идентификационные данные в форматеkey=value, положить вSet-Cookieполе вместе с ответным сообщением, отправленным в браузер.
  2. Браузер видитSet-CookieПоле позже узнает, что это идентификатор, предоставленный сервером, поэтому он сохраняется, и следующий запрос будет автоматическиkey=valueзначение вCookieполе на сервер.
  3. После того, как сервер получает сообщение запроса, он обнаруживает, чтоCookieЕсли в поле есть значение, пользователь может быть идентифицирован на основе этого значения, и может быть предоставлена ​​персонализированная услуга.

Затем мы используем код, чтобы продемонстрировать, как генерируется сервер. Мы сами создаем фоновый сервер. Здесь я использую SpringBoot для сборки, и код, написанный в SpringMVC, выглядит следующим образом.

1@RequestMapping("/testCookies")
2public String cookies(HttpServletResponse response){
3    response.addCookie(new Cookie("testUser","xxxx"));
4    return "cookies";
5}

После старта проекта вводим путьhttp://localhost:8005/testCookies, а затем просмотреть отправленный запрос. Вы можете увидеть запрос, отправленный при первом доступе к серверу на картинке ниже, и вы можете увидеть, что ответ, возвращенный сервером, содержитSet-Cookieполе. И внутриkey=valueЗначение именно то, что установлено на нашем сервере.

Затем мы снова обновляем страницу, чтобы увидеть, что она была установлена ​​в теле запроса.Cookieполе, и перенесите туда наше значение. Таким образом, сервер можетCookieЗначение в запоминает нашу информацию.

Далее, как насчет другого запроса? Да или нетCookieТы тоже возьмешь? Далее вводим путьhttp://localhost:8005просить. Мы видим, чтоCookieПоля по-прежнему переносятся.

затем браузерCookieГде он хранится? Если вы используетеChromeЕсли у вас есть браузер, выполните следующие действия.

  1. открыть на компьютереChrome
  2. В правом верхнем углу один клик更多значок ->设置
  3. Внизу щелкните高级
  4. существует隐私设置和安全性Ниже нажмите Настройки сайта
  5. нажмитеCookie-> Просмотреть всеCookie和网站数据

Затем вы можете искать управляемыйCookieданные. Таким образом, браузер управляет этим за васCookieданные, если в этот момент вы замените их наFirefoxдругие браузеры, потому чтоCookieпросто хранился вChromeвнутри, так что сервер снова в кругу.Если вы не знаете, кто вы, вы дадитеFirefoxВставьте маленькую заметку еще раз.

Настройки параметров в файлах cookie

Кстати говоря, вы должны знатьCookieЭто некоторые данные, которые сервер поручает браузеру хранить в клиенте, и эти данные обычно записывают ключевую идентификационную информацию пользователя. такCookieНеобходимо использовать другие средства для защиты, предотвращения утечки или кражи, эти средстваCookieхарактеристики.

имя параметра эффект Метод настройки серверной части
Max-Age Установите время истечения срока действия файла cookie в секундах. cookie.setMaxAge(10)
Domain Указывает доменное имя, которому принадлежит файл cookie. cookie.setDomain("")
Path Указывает путь, которому принадлежит файл cookie cookie.setPath("");
HttpOnly Сообщите браузеру, что этот файл cookie может передаваться только по Http-протоколу браузера, а другие способы доступа запрещены. cookie.setHttpOnly(true)
Secure Сообщите браузеру, что этот файл cookie может быть передан только в протоколе безопасности Https, если это Http, передача запрещена. cookie.setSecure(true)

Ниже я кратко продемонстрирую использование и феномен этих параметров.

Path

Установить какcookie.setPath("/testCookies"), то посещаемhttp://localhost:8005/testCookies, мы видим, что путь слева совпадает с указанным нами путем, поэтомуCookieОн отображается только в заголовке запроса, а затем мы посещаемhttp://localhost:8005, мы не нашлиCookieполе, этоPathпуть управления.

Domain

Установить какcookie.setDomain("localhost"), то посещаемhttp://localhost:8005/testCookiesМы обнаружили, что левая часть рисунка ниже имеетCookieполей, но мы получаем доступhttp://172.16.42.81:8005/testCookies, посмотрите на правую часть рисунка ниже, вы можете видеть, что нетCookieполе. ЭтоDomainКонтролируемая доставка доменаCookie.

Следующие несколько параметров не будут демонстрироваться один за другим, я считаю, что здесь все должны быть на своем месте.CookieЕсть какое-то понимание.

Session

Cookie хранится на стороне клиента, сеанс хранится на стороне сервера, а клиент сохраняет толькоSessionId

Выше мы знаем, чтоCookie, так как браузер прошелCookieТребование stateful реализовано, так зачем еще одно?SessionШерстяная ткань? Здесь мы представляем, что если некоторая информация об учетной записи хранится вCookieЕсли информация будет перехвачена, вся информация о нашей учетной записи будет потеряна. Так оно и появилосьSession, сохранить важную информацию в сеансеSession, браузер регистрирует толькоSessionIdОдинSessionIdСоответствует запросу сеанса.

 1@RequestMapping("/testSession")
2@ResponseBody
3public String testSession(HttpSession session){
4    session.setAttribute("testSession","this is my session");
5    return "testSession";
6}
7
8
9@RequestMapping("/testGetSession")
10@ResponseBody
11public String testGetSession(HttpSession session){
12    Object testSession = session.getAttribute("testSession");
13    return String.valueOf(testSession);
14}

Здесь мы пишем новый метод для тестированияSessionКак он генерируется, добавляем в параметры запросаHttpSession session, а затем введите в браузереhttp://localhost:8005/testSessionДоступ можно увидеть в заголовке возврата сервера вCookieсгенерировалSessionId. тогда браузер запоминает этоSessionIdВы можете взять этот идентификатор с собой при следующем посещении, и тогда вы сможете найти информацию, хранящуюся на сервере, на основе этого идентификатора.

В этот момент мы получаем доступ к путиhttp://localhost:8005/testGetSession, открытие, которое мы выше сохранили вSessionинформация в . ТакSessionКогда он истекает?

  • клиент: иCookieСрок действия тот же, если он не задан, то по умолчанию браузер закрывается и его уже нет, то есть при повторном открытии браузера в начальном заголовке запроса ничего нет.SessionId.
  • Серверная сторона: срок действия серверной стороны действительно истек, то есть серверная сторонаSessionКак долго сохраненная структура данных была недоступна, по умолчанию 30 минут.

Теперь, когда мы знаемSessionОн управляется на стороне сервера, поэтому, возможно, у вас возникнет несколько вопросов, когда вы увидите это.SessionГде он был создан?SessionВ какой структуре данных он хранится? Далее давайте посмотримSessionкак это управляется.

SessionУправление осуществляется в контейнере, что такое контейнер?Tomcat,Jettyи т.д. все контейнеры. Далее возьмем наиболее часто используемыеTomcatВозьмем примерTomcatкак это управляетсяSessionиз. существуетManageBaseизcreateSessionиспользуется для созданияSessionиз.

 1@Override
2public Session createSession(String sessionId) {
3    //首先判断Session数量是不是到了最大值,最大Session数可以通过参数设置
4    if ((maxActiveSessions >= 0) &&
5            (getActiveSessions() >= maxActiveSessions)) {
6        rejectedSessions++;
7        throw new TooManyActiveSessionsException(
8                sm.getString("managerBase.createSession.ise"),
9                maxActiveSessions);
10    }
11
12    // 重用或者创建一个新的Session对象,请注意在Tomcat中就是StandardSession
13    // 它是HttpSession的具体实现类,而HttpSession是Servlet规范中定义的接口
14    Session session = createEmptySession();
15
16
17    // 初始化新Session的值
18    session.setNew(true);
19    session.setValid(true);
20    session.setCreationTime(System.currentTimeMillis());
21    // 设置Session过期时间是30分钟
22    session.setMaxInactiveInterval(getContext().getSessionTimeout() * 60);
23    String id = sessionId;
24    if (id == null) {
25        id = generateSessionId();
26    }
27    session.setId(id);// 这里会将Session添加到ConcurrentHashMap中
28    sessionCounter++;
29
30    //将创建时间添加到LinkedList中,并且把最先添加的时间移除
31    //主要还是方便清理过期Session
32    SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);
33    synchronized (sessionCreationTiming) {
34        sessionCreationTiming.add(timing);
35        sessionCreationTiming.poll();
36    }
37    return session
38}

В этот момент мы понимаемSessionКак он был создан, и после того, как он был созданSessionбудет сохранен вConcurrentHashMapсередина. можно смотретьStandardSessionсвоего рода.

1protected Map<String, Session> sessions = new ConcurrentHashMap<>();

Все должны быть здесьSessionЕсть простое понимание.

Сессия хранится в контейнере Tomcat, поэтому, если есть несколько серверных машин, сессия не может быть разделена между несколькими машинами.В настоящее время можно использовать распределенное решение для сессий, предоставляемое Spring, которое заключается в том, чтобы поместить сессию в Редис.

Token

Sessionхранить проверяемую информацию на сервере и использоватьSessionIdсоответствующие данные,SessionIdХранится клиентом и будетSessionIdОно также приносит прошлое, поэтому реализуется соответствие состояния. иTokenСервер передает клиенту информацию о пользователе после кодировки Base64Url.Каждый раз, когда пользователь запрашивает, он будет приносить эту информацию, поэтому после того, как сервер получит эту информацию и расшифрует ее, он узнает, кто такой пользователь.Этот метод называется JWT (веб-токен Json).

Tokenпо сравнению сSessionПреимущество заключается в том, что при наличии нескольких серверных систем, поскольку клиент напрямую переносит данные при доступе, нет необходимости выполнять операцию совместного использования данных.

Преимущества токена

  1. Кратко: может пройтиURL,POSTпараметр или вHTTPОтправляются параметры заголовка, потому что объем данных небольшой, а скорость передачи также высокая
  2. Автономность: поскольку строка содержит информацию, необходимую пользователю, можно избежать множественных запросов к базе данных.
  3. Поскольку токен хранится на клиенте в виде Json, JWT является кросс-языковым.
  4. Нет необходимости сохранять информацию о сеансе на сервере, особенно подходит для распределенных микросервисов.

Структура JWT

Фактический JWT выглядит следующим образом: это очень длинная строка с.разделен на три части

JWT состоит из трех частей

Header

это объект Json, который описывает метаданные JWT, обычно следующим образом

1{
2  "alg": "HS256",
3  "typ": "JWT"
4}

В приведенном выше коде атрибут alg представляет алгоритм подписи (алгоритм), по умолчанию используется HMAC SHA256 (записывается как HS256); атрибут typ представляет тип токена (type), а токен JWT единообразно записывается как JWT.
Наконец, преобразуйте приведенный выше объект JSON в строку, используя алгоритм Base64URL.

В качестве токена (токена) JWT в некоторых случаях может быть помещен в URL-адрес (например, api.example.com/?token=xxx). В Base64 есть три символа +, / и =, которые имеют особое значение в URL-адресах, поэтому их необходимо заменить: = опускается, + заменяется на -, а / заменяется на _. Это алгоритм Base64URL.

Payload

Часть Payload также является объектом Json, который используется для хранения данных, которые на самом деле необходимо передать.JWT официально указывает следующие официальные поля для выбора.

  • iss (эмитент): Эмитент
  • exp (время истечения): время истечения
  • суб (тема): тема
  • aud (аудитория): аудитория
  • nbf (не раньше): время действия
  • iat (выпущено в): выдано в
  • jti (идентификатор JWT): число

Конечно, в дополнение к этим официально предоставленным полям мы также можем определить приватные поля самостоятельно.Ниже приведен пример

1{
2  "name": "xiaoMing",
3  "age": 14
4}

По умолчанию JWT не зашифрован, и любой может прочитать информацию, если она расшифрована Base64 в Интернете, поэтому обычно не помещайте секретную информацию в эту часть. Этот объект Json также используетсяBase64URLАлгоритм для строки

Signature

Часть Signature предназначена для подписи данных двух предыдущих частей, чтобы предотвратить подделку данных.

Сначала необходимо определить секретный ключ.Этот секретный ключ известен только серверу и не может быть передан пользователю.Затем используйте алгоритм подписи, указанный в Заголовке (по умолчанию HMAC SHA256).После расчета подписи объедините три части заголовка, полезной нагрузки и подписи в одну строку, каждая часть с.Разделите его и верните пользователю.

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

Как использовать токен в Java

Выше мы представили некоторые понятия о JWT, как его использовать дальше? Сначала введите в проект пакет Jar.

1compile('io.jsonwebtoken:jjwt:0.9.0')

Затем кодируйте следующим образом

 1// 签名算法 ,将对token进行签名
2SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
3// 通过秘钥签名JWT
4byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary("SECRET");
5Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
6Map<String,Object> claimsMap = new HashMap<>();
7claimsMap.put("name","xiaoMing");
8claimsMap.put("age",14);
9JwtBuilder builderWithSercet = Jwts.builder()
10        .setSubject("subject")
11        .setIssuer("issuer")
12        .addClaims(claimsMap)
13        .signWith(signatureAlgorithm, signingKey);
14System.out.printf(builderWithSercet.compact());

Обнаружено, что выходной токен выглядит следующим образом

1eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0IiwiaXNzIjoiaXNzdWVyIiwibmFtZSI6InhpYW9NaW5nIiwiYWdlIjoxNH0.3KOWQ-oYvBSzslW5vgB1D-JpCwS-HkWGyWdXCP5l3Ko

На этом этапе вы можете расшифровать информацию, просто найдя в Интернете веб-сайт декодирования Base64.

Суммировать

Я считаю, что это должен увидеть каждыйCookie,Session,TokenСуществует определенное понимание, а затем просмотрите важные моменты знаний

  • Файлы cookie хранятся на стороне клиента
  • Сессия хранится на сервере и может рассматриваться как список состояний. иметь уникальный идентификатор сеансаSessionId. может основываться наSessionIdСохраненная информация запрашивается на стороне сервера.
  • Сеанс вызовет проблему, то есть проблему совместного использования сеанса, когда в бэкэнде несколько машин.Решение может использовать фреймворк, предоставляемый Spring.
  • Токен похож на токен, без сохранения состояния, информация, необходимая серверу, закодирована в Base64 и помещена в токен, и сервер может напрямую декодировать содержащиеся в нем данные.

Кодовый адрес GitHub

Думаю, вы хотите прочитать

Справочная статья