[Node] Scaffolding to build a server and complete token verification

content

Use scaffolding to quickly build a node project
Use mysql connection pool to achieve interaction
with the database Use jsonwebtoken to achieve token authentication
Comprehensive case: use the introduction login page to achieve the above content

1. Quickly build a node project

We all know that expressthe frame can be efficiently developed node server, but also on the underlying build their own handwriting. However, express-generatorthe emergence of a good solution to this problem, it can be a key to generate a basic skeleton for our project, described as node scaffolding

1.1 Build the project

①: First install express globally: npm install express -g
②: Install express-generator globally: npm install express-generator -g
③: Then use the command to create the project:express token_learn(项目名称)

1.2 Modify the entry file

For many people who app.jsare accustomed to hand-operating servers, it is always unforgettable, but the entry file in this skeleton is www.js. At this point we can manually modify the app.js code to make it our entry file

Example:

var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');

const index = require('./routes/index');
const users = require('./routes/users');

const app = express();

app.use(express.json());
app.use(express.urlencoded({
    
     extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', index);
app.use('/users', users);

app.listen(3000, () => console.log('server is run 3000'))

2. Connect to mysql database

The connection pool is used here (efficient and safe)

2.1 Create connection

①: install mysqlmodule: npm i mysql
②: disposed in the connection pool project root

首先在项目根目录下创建 util 文件夹,文件夹下创建 bdconfig.js 文件

bdconfig.js

const mysql = require('mysql');

module.exports = {
    
    
    mysqlParams: {
    
    
        host: 'localhost', //域名
        port: '3306', //端口
        user: 'root', //用户名
        password: 'myroot', //密码
        database: 'nodeapi' //数据库
    },
    sySqlConnect(sql, sqlArr) {
    
    
        return new Promise((resolve, reject) => {
    
     //用Promise对象将其改造,方便接收数据
            const pool = mysql.createPool(this.mysqlParams);
            pool.getConnection((err, conn) => {
    
    
                if (err) {
    
    
                    reject(err)
                } else {
    
    
                    conn.query(sql, sqlArr, (err, data) => {
    
     //操作数据库
                        if (err) {
    
    
                            reject(err)
                        } else {
    
    
                            resolve(data)
                        }
                    })
                    conn.release() //释放连接
                }
            })
        })
    }
}
2.2 Use connection

When using, you only need to pass in sql (sql statement), sqlArr (parameter) , and you can directly use the return value to get the result after the Promise transformation

3. Token authentication

With the development of the web, session、cookiethe shortcomings of verification methods have become more and more prominent. At this time token, the power of the token is not limited to what it is 无状态, but also that it can跨域

3.1 Implementation steps

①: install jsonwebtokenmodule: npm i jsonwebtoken
②: the module is then used in the project

const dbConfig = require('../util/dbconfig');
const jwt = require('jsonwebtoken');
const secret = 'login-rule'; //秘钥规则(自定义)

token = async(req, res, next) => {
    
     //定义token验证中间件函数(应用于除登录外的每个请求)
    if (req.headers.authorization) {
    
    
        const token = req.headers.authorization;
        const {
    
     id, username } = jwt.verify(token, secret); // 对token进行解密查找
        let sql = 'select * from test where id=?';
        let sqlArr = [id];
        let result = await dbConfig.sySqlConnect(sql, sqlArr);
        if (result.length === 0) {
    
    
            res.status(200).send({
    
     msg: '用户错误' })
            return
        }
        if (username !== result[0].username) {
    
    
            res.status(200).send({
    
     msg: '用户错误' })
        } else {
    
    
            next()
        }
    } else {
    
    
        res.status(200).send({
    
     msg: '无效请求头' })
    }
}

login = async(req, res) => {
    
     //定义登录接口(因为这个请求头不携带token,所以引用在token验证中间件之前)
    let {
    
     username, password } = req.body;
    let sql = 'select * from test where username=?';
    let sqlArr = [username];
    let result = await dbConfig.sySqlConnect(sql, sqlArr);
    if (result.length) {
    
    
        if (password === result[0].password) {
    
    
            const {
    
     id, username } = result[0];
            //对token进行加密响应个客户端(参数1:传值规则;参数2:加密规则; 参数3:定义时间)
            const token = jwt.sign({
    
     id, username }, secret, {
    
     expiresIn: 60 * 60 });
            res.status(200).send({
    
     msg: '登陆成功', token: token, status: 200 });
        } else {
    
    
            res.status(200).send({
    
     msg: '登陆失败', status: 422 });
        }
    } else {
    
    
        res.status(200).send({
    
     msg: '用户名不存在', status: 401 })
    }
}

// 验证身份中间件
module.exports = {
    
    
    token,
    login
}

③: In the app.jsconfiguration in

// 写在 app.use() 之后,路由之前
app.use('/users/loginjwt', token.login); //登录接口(无需验证token,所以写在token中间件之前)
app.use(token.token);

4. Case realization token

4.1 Principle description

To ensure that the identity is unique and valid: every time the user sends a login request and the login is successful, the server will respond to the user with an encrypted token (string) containing user information (unique), at this time the user receives the token and stores the token in sessionStorage or localStorage (here). At the same time, every time the user sends another request, the local token is carried in the request header. The server-side token verification middleware intercepts the request, decrypts the token, obtains the user information and compares it with the database, and releases the information if it exists (identity verification is successful) .

4.2 Effect preview

Insert picture description here

4.3 Getting started

Write concise static pages and implement themajax 请求

login.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="../javascripts/jquery.min.js"></script>
    <title>Document</title>
</head>

<body>
    <form id="loginform">
        <input type="text" name="username">
        <input type="password" name="password">
        <input type="submit" value="登录">
    </form>
    <script>
        $(function() {
     
     
            $('#loginform').on('submit', function() {
     
     
                const formdata = $(this).serialize()
                $.ajax({
     
     
                    url: '/users/loginjwt',
                    type: 'post',
                    data: formdata,
                    success(res) {
     
     
                        if (res.status === 200) {
     
     
                            window.sessionStorage.setItem('token', res.token);
                            location.href = '/user/index.html'
                        }
                    }
                })
                return false
            })
        })
    </script>
</body>

</html>

index.html

<script>
    if (!sessionStorage.getItem('token')) {
     
     
        location.href = '/user/login.html'
    }
</script>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="../javascripts/jquery.min.js"></script>
    <title>Document</title>
</head>

<body>
    <h1>welcome index</h1>
    <a href="javascript:;">退出登录</a>
    <script>
        $(function() {
     
     
            $.ajaxSetup({
     
     
                // 发送请求前触发
                beforeSend(xhr) {
     
     
                    // 在此设置自定义请求头
                    xhr.setRequestHeader('authorization', sessionStorage.getItem('token'))
                }
            })
            $.ajax({
     
     
                url: '/users',
                success(res) {
     
     
                    console.log(res);
                }
            })
            $('a').on('click', function() {
     
     
                sessionStorage.clear();
                location.href = '/user/login.html'
            })
        })
    </script>
</body>

</html>
4.4 Notes
  1. It is noteworthy that, for local tokenauthentication (if there is) must be written at the top of the page (to prevent the page loads, the user is sent a list of requests again)
  2. For ajax请求头one plus a really annoying, here with $ajaxSetupmethods to modify the default configuration of ajax. After configuration, the ajax request written below it will bring the request header.

For technical issues, welcome to disturb,

Guess you like

Origin blog.csdn.net/cwq521o/article/details/107642892