> The author's writing skills are still shallow, if there is anything wrong, please point out generously, I will definitely be grateful
Cookie
洛:大爷,楼上322住的是马冬梅家吧?
大爷:马都什么?
夏洛:马冬梅。
大爷:什么都没啊?
夏洛:马冬梅啊。
大爷:马什么没?
夏洛:行,大爷你先凉快着吧。
Before understanding these three concepts, we must first understand that HTTP is a stateless web server. What is statelessness? Like the classic dialogue scene in Charlotte's Annoyance above, one dialogue completes and the next one has absolutely no idea what happened to the last one. If it is only used to manage static files in the Web server, it doesn't matter who the other party is, just read the file from the disk and send it out. But with the continuous development of the network, for example, the shopping cart in e-commerce can only perform the next series of actions after remembering the user's identity. So at this point we need our stateless server to remember a few things.
So how does a web server remember something? Since the Web server can't remember things, we try to remember things externally, which is equivalent to the server attaching a small note to each client. The above records some information returned by the server to us. Then the server sees this little note and knows who we are. So Cookie
who produced it? Cookies are generated by the server. Next, we describe Cookie
the process of generating
- When the browser accesses the server for the first time, the server must not know his identity at this time, so create a unique identity data in the format
key=value
, put it into theSet-Cookie
field, and send it to the browser along with the response message. - After the browser sees the
Set-Cookie
field, it knows that this is the identity ID given by the server, so it saves it, and the next time the request is made, it will automatically put thiskey=value
value into theCookie
field and send it to the server. - After the server receives the request message, it finds
Cookie
that there is a value in the field, and can identify the user's identity based on this value and provide personalized services.
Next, we use the code to demonstrate how the server is generated. We build a background server by ourselves. Here I use SpringBoot to build, and the code written into SpringMVC is as follows.
@RequestMapping("/testCookies")
public String cookies(HttpServletResponse response){
response.addCookie(new Cookie("testUser","xxxx"));
return "cookies";
}
After the project is started, we enter the path http://localhost:8005/testCookies
and then view the request sent. You can see that the image below makes the request sent when we access the server for the first time, and you can see that there are Set-Cookie
fields in the response returned by the server. The value inside is the key=value
value set in our server.
Next, we refresh the page again to see that the Cookie
field has been set in the request body, and our value has also been passed. This way the server can Cookie
remember our information based on the value in .
Next, what about another request? Will it Cookie
be brought over as well? Next we enter the path http://localhost:8005
request. We can see that the Cookie
fields are still being carried over.
So where is the browser Cookie
stored? If you are using a Chrome
browser, you can follow the steps below.
- open on computer
Chrome
- In the top right corner, click the
更多
icon once ->设置
- At the bottom, click
高级
- Below
隐私设置和安全性
, click Site Settings - Click
Cookie
-> View allCookie和网站数据
Cookie
The managed data can then be searched by domain name . So it is the data that the browser manages for you Cookie
. If you switch to Firefox
another browser at this time, because it Cookie
was stored in Chrome
it just now, the server is confused again. I don’t know who you are, and I will Firefox
post it again . Put a small note on it.
Parameter settings in cookies
At this point, you should know that the Cookie
server entrusts the browser to store some data in the client, and these data usually record the key identification information of the user. Therefore , it is Cookie
necessary to use some other means to protect and prevent leakage or theft. These means are Cookie
the attributes.
parameter name | effect | Backend setup method |
---|---|---|
Max-Age | Set the expiration time of the cookie, in seconds | cookie.setMaxAge(10) |
Domain | Specifies the domain name to which the cookie belongs | cookie.setDomain("") |
Path | Specifies the path to which the cookie belongs | cookie.setPath(""); |
HttpOnly | Tell the browser that this cookie can only be transmitted by the browser's Http protocol, and other methods of access are prohibited | cookie.setHttpOnly(true) |
Secure | Tell the browser that this cookie can only be transmitted in the Https security protocol, if it is Http, the transmission is prohibited | cookie.setSecure(true) |
Below I will briefly demonstrate the usage and phenomenon of these parameters.
Path
Set to cookie.setPath("/testCookies")
, next we visit http://localhost:8005/testCookies
, we can see that the path on the left is the same as the path we specified, so Cookie
it appears in the request header, then we visit http://localhost:8005
, we find that there is no Cookie
field, this is Path
the path of control.
Domain
Set to cookie.setDomain("localhost")
, then we visit and http://localhost:8005/testCookies
we find that Cookie
there are , but when we visit http://172.16.42.81:8005/testCookies
, look at the right side of the figure below and we can see that there Cookie
are no fields. This is the Domain
controlled domain name sending Cookie
.
The next few parameters will not be demonstrated one by one, I believe that everyone should Cookie
have some understanding here.
Session
> Cookie is stored on the client side, Session is stored on the server side, and the client only storesSessionId
What we learned above is Cookie
that since the browser has already Cookie
implemented the stateful requirement, why is there another one Session
? Here we imagine that if some information of the account is stored Cookie
in the account, once the information is intercepted, all our account information will be lost. So it appears Session
that in a session, important information is saved in Session
, and the browser only records SessionId
a SessionId
request corresponding to a session.
@RequestMapping("/testSession")
@ResponseBody
public String testSession(HttpSession session){
session.setAttribute("testSession","this is my session");
return "testSession";
}
@RequestMapping("/testGetSession")
@ResponseBody
public String testGetSession(HttpSession session){
Object testSession = session.getAttribute("testSession");
return String.valueOf(testSession);
}
Here we write a new method to test Session
how it is generated. We add it to the request parameter HttpSession session
, and then enter it in the browser to access it. You can see that one is generated in http://localhost:8005/testSession
the return header of the server . Then the browser remembers that it can take this Id with it when it next visits, and then it can find the information stored on the server based on this Id.Cookie
SessionId
SessionId
At this point, we access the path http://localhost:8005/testGetSession
and find that we get the information we stored in the above Session
. So Session
when does it expire?
- Client:
Cookie
Consistent with expiration, if it is not set, the default is to close the browser and it will be gone, that is, when the browser is opened again, the initial request header will not be thereSessionId
. - Server: The expiration of the server is really expired, that is,
Session
how long the data structure stored on the server will be unavailable. The default is 30 minutes.
Now that we know that it Session
is managed on the server side, maybe you have a few questions when you see this, Session
where was it created? Session
What data structure is it stored in? Next, let's take a look at Session
how it is managed.
Session
The management is managed in the container, what is the container? Tomcat
, Jetty
etc. are all containers. Next, let's take the most commonly used Tomcat
example to see Tomcat
how to manage Session
it. is used ManageBase
to createSession
create Session
.
@Override
public Session createSession(String sessionId) {
//首先判断Session数量是不是到了最大值,最大Session数可以通过参数设置
if ((maxActiveSessions >= 0) &&
(getActiveSessions() >= maxActiveSessions)) {
rejectedSessions++;
throw new TooManyActiveSessionsException(
sm.getString("managerBase.createSession.ise"),
maxActiveSessions);
}
// 重用或者创建一个新的Session对象,请注意在Tomcat中就是StandardSession
// 它是HttpSession的具体实现类,而HttpSession是Servlet规范中定义的接口
Session session = createEmptySession();
// 初始化新Session的值
session.setNew(true);
session.setValid(true);
session.setCreationTime(System.currentTimeMillis());
// 设置Session过期时间是30分钟
session.setMaxInactiveInterval(getContext().getSessionTimeout() * 60);
String id = sessionId;
if (id == null) {
id = generateSessionId();
}
session.setId(id);// 这里会将Session添加到ConcurrentHashMap中
sessionCounter++;
//将创建时间添加到LinkedList中,并且把最先添加的时间移除
//主要还是方便清理过期Session
SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);
synchronized (sessionCreationTiming) {
sessionCreationTiming.add(timing);
sessionCreationTiming.poll();
}
return session
}
At this point we understand Session
how to create it, and it Session
will be saved to one after it is created ConcurrentHashMap
. You can see StandardSession
classes.
protected Map<string, session> sessions = new ConcurrentHashMap<>();
Everyone should have Session
a simple understanding of it here.
> Session is stored in the Tomcat container, so if there are multiple backend machines, the session cannot be shared between multiple machines. At this time, the distributed session solution provided by Spring can be used, which is to put the session in the in Redis.
Token
Session
It stores the information to be verified on the server, and SessionId
corresponds to the data, SessionId
which is stored by the client, and will be SessionId
carried over when requested, thus realizing the correspondence of the state. InsteadToken
, the server transmits the user information to the client after Base64Url encoding. Every time the user requests, it will bring this piece of information. Therefore, after the server gets this information and decrypts it, it knows who the user is. This The method is called JWT (Json Web Token).
> The advantage of Token
comparison Session
is that when there are multiple back-end systems, since the client directly carries the data when accessing, there is no need to do the operation of sharing the data.
Advantages of Token
- Concise: It can be sent through
URL
,POST
parameter or in theHTTP
header parameter, because the amount of data is small and the transmission speed is fast - Self-contained: Because the string contains the information needed by the user, multiple database queries are avoided
- Because Token is stored on the client in the form of Json, JWT is cross-language
- No need to save session information on the server, especially suitable for distributed microservices
Structure of JWT
The actual JWT looks like the following, it is a very long string, which is .
divided into three parts in the middle
JWT is composed of three parts
Header
is a Json object that describes the metadata of the JWT, usually as follows
{
"alg": "HS256",
"typ": "JWT"
}
In the above code, the alg attribute represents the signature algorithm (algorithm), the default is HMAC SHA256 (written as HS256); the typ attribute represents the type of the token (type), and the JWT token is uniformly written as JWT. Finally, convert the above JSON object into a string using the Base64URL algorithm.
> JWT is used as a token (token), which may be placed in the URL (such as api.example.com/?token=xxx) in some cases. Base64 has three characters +, / and =, which have special meaning in the URL, so they should be replaced: = is omitted, + is replaced by -, / is replaced by _. This is the Base64URL algorithm.
Payload
The Payload part is also a Json object, which is used to store the data that actually needs to be transmitted. JWT officially stipulates the following official fields for selection.
- iss (issuer): Issuer
- exp (expiration time): expiration time
- sub (subject): subject
- aud (audience): audience
- nbf (Not Before): effective time
- iat (Issued At): Issued At
- jti (JWT ID): number
Of course, in addition to these officially provided fields, we can also define private fields by ourselves. The following is an example
{
"name": "xiaoMing",
"age": 14
}
By default, JWT is not encrypted, and anyone can read the information as long as it decodes Base64 on the Internet, so generally do not put secret information in this part. This Json object is also Base64URL
converted into a string using an algorithm
Signature
The Signature part is to sign the data of the previous two parts to prevent data tampering.
First, you need to define a secret key. This secret key is only known to the server and cannot be leaked to the user. Then, use the signature algorithm specified in the Header (the default is HMAC SHA256). After calculating the signature, combine the three parts of Header, Payload and Signature into one Strings, each part .
separated by , can be returned to the user.
> HS256 can create a signature for a given data sample with a single key. When the message is transmitted with the signature, the receiver can use the same key to verify that the signature matches the message.
How to use Token in Java
We have introduced some concepts about JWT above. How to use it next? First introduce the Jar package into the project
compile('io.jsonwebtoken:jjwt:0.9.0')
Then encode as follows
// 签名算法 ,将对token进行签名
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
// 通过秘钥签名JWT
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary("SECRET");
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
Map<string,object> claimsMap = new HashMap<>();
claimsMap.put("name","xiaoMing");
claimsMap.put("age",14);
JwtBuilder builderWithSercet = Jwts.builder()
.setSubject("subject")
.setIssuer("issuer")
.addClaims(claimsMap)
.signWith(signatureAlgorithm, signingKey);
System.out.printf(builderWithSercet.compact());
It is found that the output Token is as follows
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0IiwiaXNzIjoiaXNzdWVyIiwibmFtZSI6InhpYW9NaW5nIiwiYWdlIjoxNH0.3KOWQ-oYvBSzslW5vgB1D-JpCwS-HkWGyWdXCP5l3Ko
At this point, you can decode the information by simply looking for a Base64 decoding website on the Internet.
Summarize
I believe that everyone should have a certain understanding Cookie
of this Session
, Token
and then review the important knowledge points.
- Cookies are stored on the client side
- Session is stored on the server and can be understood as a state list. Has a unique session ID
SessionId
. The stored information can beSessionId
queried on the server side. - Session will cause a problem, that is, the problem of Session sharing when there are multiple machines in the backend. The solution can use the framework provided by Spring.
- Token is similar to a token, stateless, the information required by the server is Base64 encoded and put into the Token, and the server can directly decode the data in it.
GitHub code address
Reference article
- Cookies vs. Tokens: The Definitive Guide
- Thoroughly understand session, cookie, token
- Perspective HTTP Protocol
- Manager component: Analysis of Tomcat's Session management mechanism
- Getting Started with JSON Web Token
- SpringBoot integrates JWT to implement token verification
- JSON Web Token - securely pass information between web applications </string,object></string,>