How to use Cookie Session JWT in koa? Application and realization principle of Cookie, Session, JWT in koa.
Cookies
- The HTTP protocol is stateless, but in WEB applications, it is necessary to share sessions between multiple requests, so cookies appear
- Cookie is the data stored on the client for the purpose of identifying the user’s identity and for session tracking
The server sets cookies: when the client accesses the server for the first time, it will send cookies to the client through the response header, and the attributes are separated by semicolon spaces
The client receives and saves the cookie: when the client requests the server again, it will carry the cookie to the server, and the cookie itself is a request header
Important attributes
Simulate two different domain names by modifying the local hosts file.
# hosts 127.0.0.1 znlive.com 127.0.0.1 jhrs.com
How to use Cookie Session JWT in koa?
Attributes | instruction |
---|---|
name=value | Key-value pairs, you can Set to save Key/Value |
Domain | For a domain name to take effect, it can cross the parent domain and the subdomain,The default is the current domain name |
expires/max-age | Cookie survival time, expires absolute time, max-age relative time unit second |
secure | When the secure value is true, the cookie is invalid in HTTP and only takes effect under https |
Path | Indicates that the path affected by the cookie default is/ can be accessed. like When the path does not match, the browser will not send this cookie |
httpOnly | It means that the browser cannot be obtained through code to prevent XSS attacks, but it can be changed by manually modifying the console. |
How to use Cookie Session JWT in koa
npm install koa koa-router
How to use Cookie Session JWT in koa?
const Koa = require('koa'); const Router = require('koa-router'); const querystring = require('querystring') // used to parse and format the URL query string const app = new Koa(); const router = new Router(); // koa operation cookie implementation principle app.use(async (ctx, next) => { // Extend a method of setting cookies let cookieArr = []; ctx.req.getCookie = function (key) { let cookies = ctx.req.headers['cookie']; // name=xx; age=yy => name=xx&age=yy let cookieObj = querystring.parse(cookies,';') return cookieObj[key] ||'' } ctx.res.setCookie = function (key, value, options={}) { let args = []; // Each cookie attribute collection options.domain && args.push(`domain=${options.domain}`); options.maxAge && args.push(`max-age=${options.maxAge}`); options.httpOnly && args.push(`httpOnly=${options.httpOnly}`); options.path && args.push(`path=${options.path}`); cookieArr.push(`${key}=${value}; ${args.join(';')}`); ctx.res.setHeader('Set-Cookie', cookieArr); // string array } await next(); }) router.get('/read', async (ctx, next) => { // Encapsulate by yourself ctx.body = ctx.req.getCookie('name') ||'empty'; // koa implementation // ctx.body = ctx.cookies.get('name') ||'empty'; // Native usage // ctx.body = ctx.req.headers['cookie'] ||'empty'; // request header }) router.get('/write', async (ctx, next) => { // Encapsulate by yourself ctx.res.setCookie('name','nn', {domain:'.znlive.com'}); // Restrict accessible domain names ctx.res.setCookie('age', '12', {httpOnly: true,path:'/write'}); // Restrict accessible paths // koa implementation // ctx.cookies.set('name','nn', {domain:'.znlive.com'}); // ctx.cookies.set('age', '12', {httpOnly: true,path:'/write'}); // Native usage // ctx.res.setHeader('Set-Cookie','name=yy'); // ctx.res.setHeader('Set-Cookie','age=15'); // Set a cookie, set cookie again will overwrite the previous one // ctx.res.setHeader('Set-Cookie', ['name=yy; domain=.znlive.com','age=15; path=/; max-age=10; httpOnly=true']); // When setting multiple cookies, an array of strings can be accepted ctx.body ='write ok'; }) app.use(router.routes()) app.listen(4000);
How to use Cookie Session JWT in koa?
Cookies are usually generated by the server and exist on the client side. With each request sent to the server side, the front-end stored data can be manually tampered with by the user.
Therefore, it is possible to sign the cookie to make it relatively safe, generate an identification based on the content of the cookie, retain the original content, and add a configuration {signed: true} for each request to verify the signature
const Koa = require('koa'); const Router = require('koa-router'); const querystring = require('querystring'); const crypto = require('crypto'); const app = new Koa(); const router = new Router(); app.keys = ['ya']; // base64Url needs special treatment + = / const sign = value => crypto.createHmac('sha1',app.keys.join('')).update(value).digest('base64').replace(/\+/g,'-'). replace(/\=/g,'').replace(/\//g,'_'); app.use(async (ctx, next) => { let cookieArr = []; ctx.req.getCookie = function (key, options = {}) { let cookies = ctx.req.headers['cookie']; let cookieObj = querystring.parse(cookies,';') if(options.signed){ // The passed signature is consistent with the result obtained by the latest calculation, indicating that it has not been modified if(cookieObj[key +'.sig'] === sign(`${key}=${cookieObj[key]}`)){ return cookieObj[key]; }else { return'' } } return cookieObj[key] ||'' } ctx.res.setCookie = function (key, value, options = {}) { let args = []; let keyValue = `${key}=${value}` options.domain && args.push(`domain=${options.domain}`); options.maxAge && args.push(`max-age=${options.maxAge}`); options.httpOnly && args.push(`httpOnly=${options.httpOnly}`); options.path && args.push(`path=${options.path}`); options.signed && cookieArr.push(`${key}.sig=${sign(keyValue)}`); // Whether to enable cookie signature cookieArr.push(`${keyValue}; ${args.join(';')}`); ctx.res.setHeader('Set-Cookie', cookieArr); // string array } await next(); }) // app.keys required for signed cookies router.get('/visit', async (ctx, next) => { // Koa implementation // let count = ctx.cookies.get('visit',{ signed: true }) || 0; // let visitCount = Number(count) + 1; // ctx.cookies.set('visit', visitCount, {signed: true }); // ctx.body = `you visit ${visitCount}` // Encapsulate by yourself let count = ctx.req.getCookie('visit', {signed: true }) || 0; let visitCount = Number(count) + 1; ctx.res.setCookie('visit', visitCount, {signed: true }); ctx.body = `ya visit: ${visitCount}` }) app.use(router.routes()) app.listen(3000);
How to use Cookie Session JWT in koa?
Precautions
May be tampered with by the client verify the legality of the signature before use,
Don’t store sensitive data, Such as user password, account balance
Every time request will automatically carry cookies, try to reduce the size of cookies
Set the correct domain and pathTo reduce data transmission
Session
Is another mechanism to record customer status, the difference is in the Cookie saved in the client browser, and the session saved in the server upper
Store the user’s corresponding information on the server, the server can store sensitive information, and the session itself is cookie-based and safer than cookies
At the same time, session has no persistence function and needs to be used with database or redis
Realization principle
npm install uuid
How to use Cookie Session JWT in koa?
const Koa = require('koa'); const Router = require('koa-router'); const uuid = require('uuid'); const app = new Koa(); const router = new Router(); app.keys = ['ya'] const session = {}; // Used to store the mapping relationship between users and information, invisible to the browser const cardName ='connect_sig'; router.get('/cut', async (ctx, next) => { let id = ctx.cookies.get(cardName, {signed:true}); if(id && session[id]){ session[id].mny -= 20; ctx.body = `mny:` + session[id].mny; }else{ let cardId = uuid.v4(); session[cardId] = {mny: 500 }; ctx.cookies.set(cardName, cardId,{httpOnly:true,signed:true}); // Only one identifier is stored in the cookie, and there is no real data ctx.body = `mny 500`; } }) app.use(router.routes()) app.listen(3000);
How to use Cookie Session JWT in koa?
JWT
JSON Web Token(JWT)
It is currently the most popular cross-domain authentication solution. JWT is not encrypted by default and anyone can read it, so don’t put important information in this section.
Solve the problem: session does not support distributed architecture, cannot support horizontal expansion, only through the database to save the session data to achieve sharing. If the persistence layer fails, authentication will fail.
Advantages: The server does not save any session data, that is, the server becomes stateless, making it easier to expand.
How to use
- In the Authorization field of the HTTP request header information
Authorization: Bearer <token>
- If it is a post request, it can also be placed in the request body, depending on which authentication method the backend uses
- It is transmitted via url
https://znlive.com/pwa?token=xxxxx
, but it is generally not recommended to use it, because there will be connection sharing and security risks
composition
JWT contains .split
three parts used , How to use Cookie Session JWT in koa?
1. HeaderHeader.Payload.Signature
{ "alg": "HS256", "typ": "JWT"} // algorithm => HMAC SHA256 // type => JWT
How to use Cookie Session JWT in koa?
2. Payload content JWT stipulates 7 official fields
iss (issuer): Issuer exp (expiration time): expiration time sub (subject): Subject aud (audience): audience nbf (Not Before): effective time iat (Issued At): Issuing time jti (JWT ID): number
How to use Cookie Session JWT in koa?
3. Signature
Sign the first two parts to prevent data tampering HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
How to use Cookie Session JWT in koa?
Practical application
npm install koa-bodyparser jwt-simple
const Koa = require('koa'); const Router = require('koa-router'); const bodyParser = require('koa-bodyparser'); const jwt = require('jwt-simple'); const app = new Koa(); const router = new Router(); app.use(bodyParser()) // log in router.post('/login', async (ctx, next) => { let {username, password} = ctx.request.body; if (username =='admin' && password =='admin') { // let token = jwt.encode(username,'znlive.com'); // jwt-simple implementation let token = myJwt.encode(username,'znlive.com'); // implement it yourself ctx.body = { code: 200, data: { token, username } } } }) // Verify if there is permission router.get('/validate', async (ctx, next) => { let authorization = ctx.get('authorization'); if(authorization){ let [,token] = authorization.split(''); try{ // let r = jwt.decode(token,'znlive.com'); // jwt-simple implementation let r = myJwt.decode(token,'znlive.com'); // implement it yourself ctx.body = { code:200, data:{ username:r } } }catch{ ctx.body = { code:401, data:'token has expired' } } } }) app.use(router.routes()) app.listen(3000);
How to use Cookie Session JWT in koa?
Realization principle
// The token component consists of three segments, 1, the fixed format represents the type 2, the content 3 is the signature //'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.ImFkbWluIg.xJ0xCP2SXSaJSC-Q1PXuByHdJlBUHCNjdGRU4XW0abU' const myJwt = { sign(str,secret){ str = require('crypto').createHmac('sha256',secret).update(str).digest('base64'); return this.toBase64Escape(str); }, toBase64(content){ // object to base64 needs to be converted to buffer => base64 let source = typeof content ==='string'? content: JSON.stringify(content); return this.toBase64Escape(Buffer.from(source).toString('base64')); }, toBase64Escape(base64){ return base64.replace(/\+/g,'-').replace(/\//g,'_').replace(/\=/g,''); }, encode(username, secret){ // Converting to base64 is not for security, but for transmission on the network let header = this.toBase64({typ:'JWT',alg:'HS256'}); let content = this.toBase64(username); let sign = this.sign([header, content].join('.'),secret) return header +'.' + content +'.' + sign }, base64urlUnescape(str){ str += new Array(5-str.length% 4).join('='); return str.replace(/\-/g,'+').replace(/_/g,'/'); }, // The same content generates the same signature, you can add some expiration time and other information // A signature is generated from the content, and vice versa, the signature is verified. To know if the content has changed decode(token,secret){ let [header, content, sign] = token.split('.'); let newSign = this.sign([header, content].join('.'),secret); if(sign === newSign){ // The data in the content line2 must be reliable at this time return Buffer.from(this.base64urlUnescape(content),'base64').toString(); }else{ throw new Error('token has expired') } } }
How to use Cookie Session JWT in koa?
- The cookie feature can be automatically carried every time a request is made, and the user login function can be realized. Use cookies to identify users,
- If you simply use cookies, it is not recommended to store sensitive information if it is hijacked. (Cookies exist on the client side and are not secure, users can tamper with them)
- Each browser generally has a limit on the size of the request header. The cookie cannot be larger than 4k. If the cookie is too large, the page will be blank. Every time you visit the server, traffic will be wasted (setting cookies reasonably);
- Session: Store the user’s corresponding information on the server, the server can store sensitive information, and the session itself is cookie-based and safer than cookies;
- localStorage: The data still exists when the browser is turned off, unless it is manually cleared, there is a size limit of about 5M, and the request will not be carried;
- sessionStorage: the page will not be destroyed if it is not closed (purpose: storage of scroll bar address when single page application is accessed)
- token -> jwt -> jsonwebtoken does not require server storage, no cross-domain restrictions, it is not recommended to store sensitive information