cookie
session
originally
Because HTTP is stateless protocol, once the data exchange between the client and the server is completed, the connection will be disconnected, and the request will be re-connected, which means that the server only from the network connection is no way to know the identity of the user. To solve this problem, each new user request is issued with an ID card, and each visit is carried with the ID card, so that the server knows who is visiting and responds differently to different users.
Session tracing is a common technique used in Web programs to track a user’s entire session. Common Session tracking techniques are cookies and sessions. Cookies identify users by recording information on the client, and sessions identify users by recording information on the server.
What is a cookie?
Cookie is a state sent by the server to the user’s browser and stored on the client. It will be automatically carried to the server when the browser sends a request to the same server next time.
The following uses node as an example to set cookies
const Koa = require('koa')
const Router = require('koa-router')
const static = require('koa-static')
const app = new Koa();
const router = new Router();
app.use(static(__dirname,'/'))
router.get('/'.async ctx=>{
// Observe that the request cookie exists
console.log('cookie:',ctx.header.cookie)
/ / set the cookie
ctx.set('Set-Cookie'.'cookie1=1234')
})
app.use(router.routes())
app.listen(3000.() = > {
console.log('Port 3000 enabled');
})
Copy the code
What is session?
Session is a server-side mechanism. Let’s imagine that if some user information is stored in cookies, once the information is intercepted, all user information will be lost. Therefore, there is a Session. Important information is stored in the Session during a Session. Cookies only record the Session ID.
Session Implementation Principle
- The server creates a session on the server side when the client first accesses it, and then saves the session (we can store the session in memory, For server clusters we need to store the session in Redis), then generate a unique id for the session, and then plant the session ID in the response header
- In this step, the sessionId is signed by the back-end key to prevent the client from changing the sessionId
- When the browser receives the response, it parses the response header and saves the sessionId in the cookie. The browser will carry the cookie information of the domain name in the request header of the next HTTP request.
- When the server receives the request from the client, it will resolve the sessionId in the cookie of the request header, and then query the user information on the server according to the sessionId
koa-session
To use session in KOA, use the KOA-session middleware NPM I KOA-session-s
const Koa = require('koa')
const router = require('koa-router') ()const session = require('koa-session')
const cors = require('koa2-cors')
const bodyParser = require('koa-bodyparser')
const static = require('koa-static')
const app = new Koa();
const redisStore = require('koa-redis');
const redis = require('redis');
const redisClient = redis.createClient(6379."localhost")
const wrapper = require('co-redis')
const client = wrapper(redisClient)
// Signature key keys is used to sign cookies
app.keys = ['some secret'];
// Configure session middleware
const SESS_CONFIG = {
key: 'kkb:sess'./ / name
maxAge: 8640000./ / the period of validity
httpOnly: true.// The server is valid
signed: true / / signature
store: redisStore({ client }) // Save session to redis
}
app.use(static(__dirname + '/'));
app.use(bodyParser())
app.use(session(SESS_CONFIG,app));
app.use((ctx, next) = > {
if (ctx.url.indexOf('login') > -1) {
next()
} else {
console.log('session', ctx.session.userinfo)
if(! ctx.session.userinfo) { ctx.body = {message: "Login failed"}}else {
next()
}
}
})
router.post('/login'.async (ctx) => {
const {
body
} = ctx.request
console.log('body',body)
/ / set the session
ctx.session.userinfo = body.username;
ctx.body = {
message: "Login successful"
}
})
router.post('/logout'.async (ctx) => {
/ / delete the session
delete ctx.session.userinfo
ctx.body = {
message: "Logout system"
}
})
router.get('/getUser'.async (ctx) => {
ctx.body = {
message: "Data obtained successfully".userinfo: ctx.session.userinfo
}
})
app.use(router.routes());
app.use(router.allowedMethods());
app.listen(3000.() = >{
console.log('Port 3000 enabled')});Copy the code
Why store sessions in Redis here?
The disadvantages of KOS-session are that the session information is not encrypted and stored in the client cookie. The browser cookie has a length limit, so we need to store the session in external storage.
How does the session-cookie approach work?
- When a user logs in, the server generates a unique session id and stores data with it as the key
- Session ids are transmitted between the client and server using cookies
- The server obtains session information through the session ID and responds to the request from the client. If no valid session is found, the user is not logged in
- Sessions have an expiration date and can be deleted by some action (such as logout)
What is a token?
Tokens are resource credentials needed to access resource interfaces (apis).
How is token different from session?
- Sessions require the server to store information and be able to retrieve it by ID, whereas tokens do not (because the information is in the token, thus making the server stateless). In large-scale systems, retrieving session information for each request can be a complex and time-consuming process. On the other hand, to resolve user identity through token, the server needs to define the corresponding protocol (such as JWT).
- Session exchanges are generally conducted through cookies, while tokens are more flexible. They can be cookies, headers, or included in requests. Not using cookies brings cross-domain convenience
- Token generation is more diversified and can be provided by third-party modules
- If the token is stolen, the server cannot detect the token. The cookie information is stored on the user’s computer and the risk of token theft is small
Token principle
- The client requests login using the username and password
- The server receives a request to verify the user name and password
- After successful authentication, the server issues a Token and sends the Token to the client
- The client receives
Token
In the future, put it in storage, for examplecookie
orlocalStore
In the - Each time a client requests a resource from a server, it needs to carry the server’s signature
Token
- The server receives the request and verifies the Token in the request. If the verification succeeds, it returns the requested data to the client
Use koA simulation interface
Installation depends on NPM I JSONWebToken KOa-JwT-s
Back-end code:
const Koa = require('koa')
const Router = require('koa-router')
const static = require('koa-static')
const bodyParser = require('koa-bodyparser')
const cors = require('koa2-cors')
const jwt = require('jsonwebtoken')
const jwtAuth = require('koa-jwt')
// Back-end key
const secret = 'balabal ssadhd'
const app = new Koa();
const router = new Router();
app.use(static(__dirname + '/'))
app.use(bodyParser())
router.post('/login-token'.async ctx => {
const {body} = ctx.request;
const userinfo = body.username;
ctx.body = {
message:'Login successful'.user:userinfo,
token:jwt.sign( / / token is generated
{
// User information
data:userinfo,
// Set the token validity period
exp:Math.floor(Date.now() / 1000) + 60 * 60
},
secret
)
}
});
router.get('/getUser-token',jwtAuth({secret}),async ctx => {
// Verify that the token passes
console.log(ctx.state.user)
ctx.body = {
message:'Data obtained successfully'.userinfo:ctx.state.user.data
}
})
app.use(router.routes())
app.use(router.allowedMethods())
app.listen(3000.() = > {
console.log('Port 3000 enabled')})Copy the code
Front-end code:
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<div>
<input v-model="username" />
<input v-model="password" />
</div>
<div>
<button v-on:click="login">Login</button>
<button v-on:click="logout">Logout</button>
<button v-on:click="getUser">GetUser</button>
</div>
<div>
<button @click="logs=[]">Clear Log</button>
</div>
<! - log - >
<ul>
<li v-for="(log,idx) in logs" :key="idx">
{{ log }}
</li>
</ul>
</div>
<script>
axios.interceptors.request.use(
config= > {
const token = window.localStorage.getItem("token");
if (token) {
// Determine whether a token exists, and if so, add a token to each HTTP header
// Bearer is a confirmed header of JWT
config.headers.common["Authorization"] = "Bearer " + token;
}
return config;
},
err= > {
return Promise.reject(err); }); axios.interceptors.response.use(response= > {
app.logs.push(JSON.stringify(response.data));
return response;
},
err= > {
app.logs.push(JSON.stringify(response.data));
return Promise.reject(err); });var app = new Vue({
el: "#app".data: {
username: "test".password: "test".logs: []},methods: {
async login() {
const res = await axios.post("/login-token", {
username: this.username,
password: this.password
});
localStorage.setItem("token", res.data.token);
},
async logout() {
localStorage.removeItem("token");
},
async getUser() {
await axios.get("/getUser-token"); }}});</script>
</body>
</html>
Copy the code
Let’s take a look at the implementation
- When the user logs in, the server generates a token and returns it to the client
- Subsequent requests from the client carry this token in their headers
- The server parses and verifies the token to obtain user information and responds to user requests
- The token has an expiration date and will be discarded when the user logs out. However, no operation is required on the server
What is JWT?
JSON Web Token (JWT for short) is the most popular cross-domain authentication solution. JWT represents that all user data is stored on the client and every request is sent back to the server.
Refer to Nguyen Yifeng’s JWT primer