1. What is
json web token
Copy the code
Advantages:
- No state,
- Cross domain,
- Can convert JSON objects into tokens through JWT and restore JSON objects
- Encryption security
2. The format
- header.payload.signature
- Such as: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJiMDhmODZhZi0zNWRhLTQ4ZjItOGZhYi1jZWYzOTA0NjYwYmQifQ.-xN_h82PHVTCMA9v doHrcZxH-x5mb11y1537t3rGzcM
1. Header encryption mode
- Represents the encryption that can be decrypted, a JSON object that describes the metadata of the JWT
- Declare type, in this case JWT
- Algorithms that declare encryption usually use HMAC SHA256 directly
Such as: {"typ":"JWT"."alg":"HS256"}
Copy the code
2. Payload Transmits the content
- Represents the specific transmission content can be decrypted, a JSON object
- 3 Components
- A declaration of registration in a standard
- Public statement
- Private declaration
// Include the user information to be passed;
{
/ / standard
"iss": "Online JWT Builder"."iat": 1416797419."exp": 1448333419."aud": "www.gusibi.com"."sub": "uid".// Public/private
"nickname": "goodspeed"."username": "goodspeed"."scopes": [ "admin"."user"]}Copy the code
3. Sign signature
- Signature: Encrypts (payload+secret) = encrypts results using the encryption method described in the header
- The secret private key is saved by the user
4. JWT control flow chart of Egg
3. The actual combat
1. The client requests Settings
Vue /nuxt sets the header information
// /plugins/axios.js
import Vue from 'vue'
import axios from 'axios'
let service = axios.create({
timeout:5000./ / prefix
baseURL:'/api'
})
const TOKEN_KEY = 'USER_TOKEN'
// @todo interceptor manages tokens
export default({store, redirect})=>{
// Request interception
service.interceptors.request.use(
config= >{
// Request a token
const token = window.localStorage.getItem(TOKEN_KEY)
// Set the URL whitelist
if(token){
config.headers.common['Authorization'] = 'Bearer '+token // Add Bearer space format used by JWT
}
return config
},
err= >{
return Promise.reject(err)
}
)
}
Copy the code
2.1 Egg-JWT back-end implementation
NPM I egg-jwt-s // install libraryCopy the code
//config/plugin.js
jwt:
{ enable: true.package: 'egg-jwt',}//config/config.default.js
config.jwt = {
secret: 'Great4-M'.enable: true.// default is false
match: /^\/api/.// optional
}
//service/actionToken.js
// Generate a token. The _id is the database ID
const { Service } = require('egg')
class ActionTokenService extends Service {
async apply(_id) {
const { ctx } = this
return ctx.app.jwt.sign({
data: {
_id: _id
},
exp: Math.floor(Date.now() / 1000 + (60 * 60 * 7))
}, ctx.app.config.jwt.secret)
}
}
module.exports = ActionTokenService
//service/userAccess.js
const { Service } = require('egg')
class UserAccessService extends Service {
async login(payload) {
const { ctx, service } = this
const user = await service.user.findByMobile(payload.mobile)
console.log('88888mobile'+payload.moblie)
if(! user) { ctx.throw(404.'user not found')}let verifyPsw = await ctx.compare(payload.password, user.password)
if(! verifyPsw) { ctx.throw(404.'user password is error')}// Generate a Token
return { token: await service.actionToken.apply(user._id) }
}
async logout(){}async current() {
const { ctx, service } = this
// ctx.state.user can extract jWt-encoded data
const _id = ctx.state.user.data._id
const user = await service.user.find(_id)
if(! user) { ctx.throw(404.'user is not found')
}
user.password = 'How old are you? '
return user
}
}
module.exports = UserAccessService
// app/contract/userAccess.js
module.exports = {
loginRequest: {
mobile: { type: 'string'.required: true.description: 'Mobile phone Number'.example: '1880000000'.format: /^1[34578]\d{9}$/,},password: { type: 'string'.required: true.description: 'password'.example: '111111',,}}}//controller/userAccess.js
'use strict'
const Controller = require('egg').Controller
/ * * *@Controller User authentication */
class UserAccessController extends Controller {
constructor(ctx) {
super(ctx)
}
/ * * *@summary User Login@description User Login@router post /auth/jwt/login
* @request body loginRequest *body
* @response 200 baseResponse created successfully */
async login() {
const { ctx, service } = this
// Check parameters
ctx.validate(ctx.rule.loginRequest);
// Assemble parameters
const payload = ctx.request.body || {}
// Call Service for business processing
const res = await service.userAccess.login(payload)
// Set the response content and response status code
ctx.helper.success({ ctx, res })
}
/ * * *@summary User logs out *@description User logs out *@router post /auth/jwt/logout
* @request body loginRequest *body
* @response 200 baseResponse created successfully */
async logout() {
const { ctx, service } = this
// Call Service for business processing
await service.userAccess.logout()
// Set the response content and response status code
ctx.helper.success({ ctx })
}
}
module.exports = UserAccessController
Copy the code
2.2 Custom registration middleware, egg back-end implementation
NPM I jsonWebToken -s // install JWTCopy the code
server/config/config.default.js
module.exports = appInfo= > {
return{... config, ... userConfig,jwt: {
secret: 'xxxxxxx'.// Define configuration information}}},//app/middleware/jwt.js
// The middleware that parses tokens can also use egg-jwt, which is more suitable for understanding the principle
const jwt = require('jsonwebtoken')
module.exports = ({ app }) = > {
return async function verify(ctx, next) {
if(! ctx.request.header.authorization) { ctx.body = {code: -Awesome!.message: 'User not logged in',}return
}
const token = ctx.request.header.authorization.replace('Bearer '.' ')
try {
const ret = await jwt.verify(token, app.config.jwt.secret)
ctx.state.email = ret.email
ctx.state.userid = ret._id
await next()
} catch (err) {
console.log(err)
if (err.name === 'TokenExpiredError') {
ctx.body = {
code: -Awesome!.message: 'Login expired',}}else {
ctx.body = {
code: -1.message: 'User information error',}}}}}//app/router.js
module.exports = app= > {
const { router, controller } = app
const jwt = app.middleware.jwt({ app })
router.get('/', controller.home.index)
router.group({ name: 'user'.prefix: '/user' }, router= > {
const {
info,login, register,
} = controller.user
router.post('/register', register)
router.post('/login', login)
router.get('/info', jwt, info) // Add JWT validation for those requiring authentication}}//app/controller/user.js
const md5 = require('md5')
const jwt = require('jsonwebtoken')
const BaseController = require('./base')
const HashSalt = 'xxxxxx11223'
class UserController extends BaseController {
async login() {
// this.success('token')
const { ctx, app } = this
const { email, captcha, passwd, emailcode } = ctx.request.body
const user = await ctx.model.User.findOne({
email,
passwd: md5(passwd + HashSalt),
})
if(! user) {return this.error('Wrong username and password')}// The user's information is encrypted into a token and returned
const token = jwt.sign({
_id: user._id,
email,
}, app.config.jwt.secret, {
expiresIn: '100h',})this.success({ token, email, nickname: user.nickname })
}
}
module.exports = UserController
Copy the code