NodeJS:圖片驗證碼登陸

效果展現

樣式可能有點醜,請不要在乎html

用到的技術

express、vue、redis、axios前端

功能實現

圖片驗證碼生成

svg-captcha是一個能夠生成圖形驗證碼的模塊,詳細介紹移步svg-captcha文檔vue

下載svg-captcha模塊node

npm i svg-captcha -S
複製代碼

在nodejs中引入ios

const code = require("svg-captcha");
複製代碼

以後對模塊進行配置並導出git

const code = require("svg-captcha");
function createCode() {
    return code.create({
        size: 4,
        ignoreChars: "0o1iIl",
        noise: 3,
        color: true,
        background: "#fff",
        fontSize: 60
    });
}
module.exports = createCode;
複製代碼

模塊導出後在後端路由模塊中引入生成圖片驗證碼的模塊github

const captcha = require("./Code")
複製代碼

svg-captcha的實例,給咱們提供了兩個屬性redis

  • data:驗證碼svg
  • text:驗證碼文本

咱們要讓前端顯示的確定是svg格式的圖片,不多是text文本,由於若是要爬蟲模擬登陸,豈不是太簡單了?數據庫

以後訪問驗證碼接口地址,就能夠看到圖片了。express

前端頁面代碼

全部框架和工具,我引的都是CND

html部分

<div id="app">
    <p><label>用戶名:</label><input type="text" ref="username" value="Wick"></p>
    <p><label>密碼:</label><input type="text" ref="password" value="123456"></p>
    <p id="code">
        <label>驗證碼:</label>
        <input ref="codeValue" type="text">
        <img @click="getCode" :src="codeImg" alt="">
    </p>
    <button id="login" @click="login">登陸</button>
</div>
複製代碼

js部分

axios.defaults.baseURL = "http://localhost:10086";
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
axios.defaults.withCredentials = true;
axios.interceptors.request.use(config => {
    return config;
})
const app = new Vue({
    el: "#app",
    data: {
        codeImg: `http://localhost:10086/code?t=${new Date().getTime()}`
    },
    methods: {
        getCode() {
            // 添加時間戳進行驗證碼切換
            this.codeImg = `http://localhost:10086/code?t=${new Date().getTime()}`;
            this.$refs.codeValue.value = "";
        },
        login() {
            let username = this.$refs.username.value;
            let password = this.$refs.password.value;
            let code = this.$refs.codeValue.value;
            let data = {
                username,
                password: CryptoJS.AES.encrypt(password, username).toString(),   //密碼加密
                code
            }
            axios.post("/login", Qs.stringify(data)).then(res => {
                alert(res.data.msg);
                if(res.data.success === "ok") {
                    window.location = "/Home.html";
                }
            })
        }
    }
});
複製代碼

引入express-session

原生nodejs未提供session功能,因此咱們只能引入第三方模塊express-session

下載express-session

npm i -S express-session
複製代碼

nodejs引入express-session

const session = require("express-session");
複製代碼

中間件設置,詳細配置移步express-session文檔

app.use(session({
    secret: "WickYo",	// 對cookie進行簽名
    name: "session",	// cookie名稱,默認爲connect.sid
    resave: false,	// 強制將會話保存回會話容器
    rolling: true,	// 強制在每一個response上設置會話標識符cookie
    cookie: {
        // 5分鐘
     	maxAge: 300000
    }
}))
複製代碼

配置以後,頁面的response都會帶有這個session

查看一下Application裏的cookies

這裏的session的存活時間,我是用來作驗證碼是否失效的,當session過時了,那麼驗證碼也就跟着失效,那麼就須要切換驗證進行登陸

引入redis並設置驗證碼

下載redis模塊

npm i redis -S
複製代碼

nodejs中引入

const redis = require("redis");
複製代碼

對redis進行配置,這裏只是簡單配置,詳細移步redis文檔

const client = redis.createClient({
    host: "192.168.56.101",	// redis地址
    port: 6379	// 端口號
})
// 監聽鏈接事件
client.on("connect", error => {
    if(!error) {
        console.log("connect to redis")
    }
})
// 監聽錯誤事件
client.on("error", error => {
    throw new Error(error)
})
複製代碼

封裝set方法

function setString(key, value, expire) {
    return new Promise((resolve, reject) => {
        client.set(key, value, (error, replay) => {
            if(error) {
                reject("設置失敗")
            }
            if(expire) {
                client.expire(key, expire);
            }
            resolve("設置成功")
        });
    })
}
複製代碼

封裝get方法

function getString(key) {
    return new Promise((resolve, reject) => {
        if(key) {
            client.get(key, (error, replay) => {
                if(error) {
                    reject(`獲取${key}失敗`)
                }
                resolve(replay);
            })
        }
    })
}
複製代碼

最後導出方法。

module.exports = {
    setString,
    getString
}
複製代碼

上面封裝了set和get方法,那麼咱們就能夠在redis中設置值了。

通過前面的express-session配置以後,咱們在進入頁面時,就會加載驗證碼圖片並設置cookie(存着sessionID的值),而後在登陸的時候,會帶上這個cookie。那這樣,咱們就能夠在獲取圖片的時候,以sessionID值爲key,svg-captcha的text爲value進行設置

注:sessionID是使用了express-session後注入的

登陸功能實現

爲了方便,就不鏈接數據庫了,直接建立一個本地的文件當作用戶的帳號密碼吧

直接上代碼

Router.post("/login", (req, res) => {
    let username = req.body.username;
    let password = CryptoJS.AES.decrypt(req.body.password, username).toString(CryptoJS.enc.Utf8);   // 解密
    let code = req.body.code.toLowerCase();
    if(!req.signedCookies.session) {
        res.send({success: "no", msg: "驗證碼過時"})
        return;
    }
    // redis封裝的方法
    getString(req.signedCookies.session).then(data => {
        // signedCookies即被簽名過的cookie
        console.log(data)
        if(code === data) {
            console.log("驗證碼正確")
            // 讀文件
            fs.readFile(__dirname + "/../user.conf", "utf8", (err, data) => {
                let dataArr = data.toString().split("=");
                if(username === dataArr[0]) {
                    if(password === dataArr[1]) {
                        // 根據登陸用戶名設置cookie,並規定只能cookie存活30分鐘
                        res.cookie("uid", username, {maxAge: 300000})
                        res.send({success: "ok", msg: "登陸成功"})
                        return;
                    }
                }
                res.send({success: "no", msg: "用戶名或密碼錯誤"})
            })
        } else {
            res.send({success: "no", msg: "驗證碼錯誤"})
        }
    }).catch(err => {
        console.log(err)
    })
})
複製代碼

引入cookie-parser

咱們能夠引入cookie-parse對cookie進行解密

中間件設置

app.use(cookieParser(secret))
複製代碼

配置好以後,就能解析出被指定secret加密過的cookie了

獲取post請求參數

咱們沒辦法直接獲取到post的參數,須要安裝body-parser模塊,才能進行獲取

npm i -S body-parser
複製代碼

配置body-parser

app.use(bodyParser.urlencoded({ extended: false }))	//解析application/x-www-form-urlencoded
複製代碼

配置以後,咱們就能獲取到請求體了

什麼是Signed cookie?

cookie有一個很差地方的,就是在瀏覽器中可見,而且是能夠修改的,若是咱們直接把敏感信息存儲在cookie中,那麼任何人均可見,任何人均可對其進行修改,這是很不安全的。

正是由於不安全,因此纔會須要簽名Cookie(Signed Cookie)對其進行加密,以防止被某些信息被泄露。

咱們手動對加密後的cookie進行解密

解密出來的值,其實就是在獲取驗證碼時的sessionID。

因此,咱們能經過req.signedCookies獲取對應的cookie,都是由於cookie-parser幫咱們作了解密。

本文已收錄至github:github.com/OnlyWick/Fu…

若有錯誤,請及時指出!

相關文章
相關標籤/搜索