成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

聊聊畢業(yè)設(shè)計(jì)系列 --- 系統(tǒng)實(shí)現(xiàn)

null1145 / 1869人閱讀

摘要:七牛云接入本系統(tǒng)的圖片,音視頻是放在七牛云,所以需要接入七牛云。在服務(wù)端通過(guò)接口請(qǐng)求來(lái)獲取七牛云上傳,客戶端獲取到七牛云,通過(guò)不同方案將帶上。

效果展示

github

moment-server github地址

moment github地址

moment-manage github地址

articles

聊聊畢業(yè)設(shè)計(jì)系列 --- 項(xiàng)目介紹

聊聊畢業(yè)設(shè)計(jì)系列 --- 系統(tǒng)實(shí)現(xiàn)

前言

在上一篇文章中,主要是對(duì)項(xiàng)目做了介紹,并且對(duì)系統(tǒng)分析和系統(tǒng)設(shè)計(jì)做了大概的介紹。那么接下來(lái)這篇文章會(huì)對(duì)系統(tǒng)的實(shí)現(xiàn)做介紹,主要是選擇一些比較主要的模塊或者說(shuō)可拿出來(lái)與大家分享的模塊。好了,接入正題吧~~

MongoDB

服務(wù)端這邊使用的是Express框架,數(shù)據(jù)庫(kù)使用的是MongoDB,通過(guò)Mongoose模塊來(lái)操作數(shù)據(jù)庫(kù)。這邊主要是想下對(duì)MongoDB做個(gè)介紹,當(dāng)然看官了解的話直接往下劃~~

在項(xiàng)目開(kāi)始前要確保電腦是否安裝mongoDB,下載點(diǎn)我,圖像化工具Robo 3T 點(diǎn)我,下載好具體怎么配置還請(qǐng)問(wèn)度娘或Google吧,本文不做介紹了哈。注意:安裝完mongoDB的時(shí)候進(jìn)行項(xiàng)目時(shí)要把lib目錄下的mongod服務(wù)器打開(kāi)哈~~

MongoDB 是一個(gè)基于分布式文件存儲(chǔ)的數(shù)據(jù)庫(kù),是一個(gè)介于關(guān)系型數(shù)據(jù)庫(kù)和非關(guān)系型數(shù)據(jù)庫(kù)之間的開(kāi)源產(chǎn)品,它是功能最為豐富的非關(guān)系型數(shù)據(jù)庫(kù),也是最像關(guān)系型數(shù)據(jù)庫(kù)的。但是和關(guān)系型數(shù)據(jù)庫(kù)不同,MongoDB沒(méi)有表和行的概念,而是一個(gè)面向集合、文檔的數(shù)據(jù)庫(kù)。其中的文檔是一個(gè)鍵值對(duì),采用BSON(Binary Serialized Document Format),BSON是一種類似于JSON的二進(jìn)制形式的存儲(chǔ)格式,并且BSON具有表示數(shù)據(jù)類型的擴(kuò)展,因此支持的數(shù)據(jù)非常豐富。MongoDB有兩個(gè)很重要的數(shù)據(jù)類型就是內(nèi)嵌文檔和數(shù)組,而且在數(shù)組內(nèi)可以嵌入其他文檔,這樣一條記錄就能表示非常復(fù)雜的關(guān)系。

Mongoose是在node.js異步環(huán)境下對(duì)MongoDB進(jìn)行簡(jiǎn)便操作的對(duì)象模型工具,能從數(shù)據(jù)庫(kù)提取任何信息,可以用面向?qū)ο蟮姆椒▉?lái)讀寫(xiě)數(shù)據(jù),從而使操作MongoDB數(shù)據(jù)庫(kù)非常便捷。Mongoose中有三個(gè)非常重要的概念,便是Schema(模式),Model(模型),Entity(實(shí)體)。

Schema: 一種以文件形式存儲(chǔ)的數(shù)據(jù)庫(kù)模型骨架,不具備數(shù)據(jù)庫(kù)的操作能力,創(chuàng)建它的過(guò)程如同關(guān)系型數(shù)據(jù)庫(kù)建表的過(guò)程,如下:

//Schema
const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const UserSchema = new Schema({
    token: String,
    is_banned: {type: Boolean, default: false}, //是否禁言
    enable: { type: Boolean, default: true }, //用戶是否有效
    is_actived: {type: Boolean, default: false}, //郵件激活
    username: String,
    password: String,
    email: String,  //email唯一性
    code: String,
    email_time: {type: Date},
    phone: {type: String},
    description: { type: String, default: "這個(gè)人很懶,什么都沒(méi)有留下..." },
    avatar: { type: String, default: "http://p89inamdb.bkt.clouddn.com/default_avatar.png" },
    bg_url: { type: String, default: "http://p89inamdb.bkt.clouddn.com/FkagpurBWZjB98lDrpSrCL8zeaTU"},
    ip: String,
    ip_location: { type: Object },
    agent: { type: String }, // 用戶ua
    last_login_time: { type: Date },
    .....
});

Model: 由Schema發(fā)布生成的模型,具有抽象屬性和行為的數(shù)據(jù)庫(kù)操作對(duì)象

//生成一個(gè)具體User的model并導(dǎo)出
const User = mongoose.model("User", UserSchema);  //第一個(gè)參數(shù)是集合名,在數(shù)據(jù)庫(kù)中會(huì)把Model名字字母全部變小寫(xiě)和在后面加復(fù)數(shù)s

//執(zhí)行到這個(gè)時(shí)候你的數(shù)據(jù)庫(kù)中就有了 users 這個(gè)集合

module.exports = User;

Entity: 由Model創(chuàng)建的實(shí)體,他的操作也會(huì)影響數(shù)據(jù)庫(kù),但是它操作數(shù)據(jù)庫(kù)的能力比Model弱

const newUser = new UserModel({          //UserModel 為導(dǎo)出來(lái)的 User
            email: req.body.email,
            code: getCode(),
            email_time: Date.now()
        }); 

Mongoose中有一個(gè)東西個(gè)人感覺(jué)非常主要,那便是populate,通過(guò)populate他可以很方便的與另一個(gè)集合建立關(guān)系。如下,user集合可以與article集合、user集合本身進(jìn)行關(guān)聯(lián),根據(jù)其內(nèi)嵌文檔的特性,這樣子他便可以內(nèi)嵌子文檔,子文檔中有可以內(nèi)嵌子文檔,這樣子它返回的數(shù)據(jù)就會(huì)異常的豐富。

const user = await UserModel.findOne({_id: req.query._id, is_actived: true}, {password: 0}).populate({
                path: "image_article",
                model: "ImageArticle",
                populate: {
                    path: "author",
                    model: "User"
                }
            }).populate({
                path: "collection_film_article",
                model: "FilmArticle",
            }).populate({
                path: "following_user",
                model: "User",
            }).populate({
                path: "follower_user",
                model: "User",
            }).exec();

服務(wù)端主要是操作數(shù)據(jù)庫(kù),對(duì)數(shù)據(jù)庫(kù)進(jìn)行增刪改查(CRUD)等操作。項(xiàng)目中的接口,Mongoose的各種方法這邊就不對(duì)其做詳細(xì)介紹,大家可以查看Mongoose文檔。

用戶身份認(rèn)證實(shí)現(xiàn) 介紹

本系統(tǒng)的用戶身份認(rèn)證機(jī)制采用的是JSON Web Token(JWT),它是一種輕量的認(rèn)證規(guī)范,也用于接口的認(rèn)證。我們知道,HTTP協(xié)議是一種無(wú)狀態(tài)的協(xié)議,這便意味著每個(gè)請(qǐng)求都是獨(dú)立的,當(dāng)用戶提供了用戶名和密碼來(lái)對(duì)我們的應(yīng)用進(jìn)行用戶認(rèn)證,那么在下一次請(qǐng)求的時(shí)候,用戶需要再進(jìn)行一次用戶的認(rèn)證才可以,因?yàn)楦鶕?jù)HTTP協(xié)議,我們并不能知道是哪個(gè)用戶發(fā)出的請(qǐng)求,本系統(tǒng)采用了token的鑒權(quán)機(jī)制。這個(gè)token必須要在每次請(qǐng)求時(shí)傳遞給服務(wù)端,它應(yīng)該保存在請(qǐng)求頭里,另外,服務(wù)端要支持CORS(跨來(lái)源資源共享)策略,一般我們?cè)诜?wù)端這么做就可以了Access-Control-Allow-Origin: *。

在用戶身份認(rèn)證這一塊有很多方法,最常見(jiàn)的像cookie ,session。那么他們?nèi)g又有什么區(qū)別,這里有兩篇文章介紹的挺全面。

正確理解HTTP短連接中的Cookie、Session和Token

小白必讀:閑話HTTP短連接中的Session和Token

token 與 session的區(qū)別在于,它不同于傳統(tǒng)的session認(rèn)證機(jī)制,它不需要在服務(wù)端去保留用戶的認(rèn)證信息或其會(huì)話的信息。系統(tǒng)一旦比較大,都會(huì)采用機(jī)器集群來(lái)做負(fù)載均衡,這需要多臺(tái)機(jī)器,由于session是保存在服務(wù)端,那么就要 去考慮用戶到底是在哪一臺(tái)服務(wù)器上進(jìn)行登錄的,這便是一個(gè)很大的負(fù)擔(dān)。

那么就有人想問(wèn)了,你這個(gè)系統(tǒng)這么小,為什么不使用傳統(tǒng)的session機(jī)制呢?哈~因?yàn)橹白约旱捻?xiàng)目一般都是使用session做登錄,沒(méi)使用過(guò)token,想嘗試嘗試入入坑~~哈哈哈~

實(shí)現(xiàn)思路

JWT主要的實(shí)現(xiàn)思路如下:

在用戶登錄成功的時(shí)候創(chuàng)建token保存于數(shù)據(jù)庫(kù)中,并返回給客戶端。

客戶端之后的每一次請(qǐng)求都要帶上token,在請(qǐng)求頭里加入Authorization,并加上token.

在服務(wù)端進(jìn)行驗(yàn)證token的有效性,在有效期內(nèi)返回200狀態(tài)碼,token過(guò)期則返回401狀態(tài)碼

如下圖所示:


JWT請(qǐng)求圖

在node中主要用了jsonwebtoken這個(gè)模塊來(lái)創(chuàng)建JWT,jsonwebtoken的使用請(qǐng)查看jsonwebtoken文檔。項(xiàng)目中創(chuàng)建token的中間件createToken如下

/**
 * createToken.js
 */
const jwt = require("jsonwebtoken");  // 引入jsonwebtoken模塊
const secret = "我是密鑰"

//登錄時(shí):核對(duì)用戶名和密碼成功后,應(yīng)用將用戶的id(user_id)作為JWT Payload的一個(gè)屬性
module.exports = function(user_id){
    const token = jwt.sign({
        user_id: user_id
    }, secret, {  //密鑰
        expiresIn: "24h" //過(guò)期時(shí)間設(shè)置為24h。那么decode這個(gè)token的時(shí)候得到的過(guò)期時(shí)間為:創(chuàng)建token的時(shí)間+設(shè)置的值
    });
    return token;
};

return 出來(lái)的 token 類似eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiYWRtaW4iLCJpYXQiOjE1MzQ2ODQwNzAsImV4cCI6MTUzNDc3MDQ3MH0.Y3kaglqW9Fpe1YxF_uF7zwTV224W4W97MArU0aI0JgM。我們仔細(xì)看這字符串,分為三段,分別被 "." 隔開(kāi)?,F(xiàn)在我們分別對(duì)前兩段進(jìn)行base64解碼如下:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9  ===> {"alg":"HS256","typ":"JWT"}  其中 alg是加密算法名字,typ是類型

eyJ1c2VyX2lkIjoiYWRtaW4iLCJpYXQiOjE1MzQ2ODQwNzAsImV4cCI6MTUzNDc3MDQ3MH0  ===>  {"user_id":"admin","iat":1534684070,"exp":1534770470}  其中 name是我們儲(chǔ)存的內(nèi)容,iat創(chuàng)建的時(shí)間戳,exp到期時(shí)間戳。

Y3kaglqW9Fpe1YxF_uF7zwTV224W4W97MArU0aI0JgM  ===> 最后一段是由前面兩段字符串,HS256加密后得到。所以前面的任何一個(gè)字段修改,都會(huì)導(dǎo)致加密后的字符串不匹配。

當(dāng)我們根據(jù)用戶的id創(chuàng)建獲取到token之后,我們需要把token返回到客戶端,客戶端對(duì)其在本地(localStorage)保存, 客戶端之后的每一次請(qǐng)求都要帶上token,在請(qǐng)求頭里加入Authorization,并加上token,服務(wù)端進(jìn)行驗(yàn)證token的有效性。那么我們?nèi)绾悟?yàn)證token的有效性呢? 所以我們需要checkToken這個(gè)中間件來(lái)檢測(cè)token的有效性。

/**
 * checkToken
 */
const jwt = require("jsonwebtoken");
const secret = "我是密鑰"

module.exports = async ( req, res, next ) => {
    const authorization = req.get("Authorization");
    if (!authorization) {
        res.status(401).end();  //接口需要認(rèn)證但是有沒(méi)帶上token,返回401未授權(quán)狀態(tài)碼
        return
    }
    const token = authorization.split(" ")[1];
    try {
        let tokenContent = await jwt.verify(token, secret);   //如果token過(guò)期或驗(yàn)證失敗,將拋出錯(cuò)誤
        next();     //執(zhí)行下一個(gè)中間件
    } catch (err) {
        console.log(err)
        res.status(401).end();  //token過(guò)期或者驗(yàn)證失敗返回401狀態(tài)碼
    }
}

那么現(xiàn)在咱們只要在需要用戶認(rèn)證的接口上,在操作數(shù)據(jù)之前,加上checkToken中間件即可,如下調(diào)用:

//更新用戶信息
router.post("/updateUserInfo", checkToken, User.updateUserInfo)  

//如果checkToken檢測(cè)不成功,它便返回401狀態(tài)碼,不會(huì)對(duì)User.updateUserInfo做任何操作, 只有檢測(cè)token成功,才能處理User.updateUserInfo

我們?nèi)绾伪WC每次請(qǐng)求都能在請(qǐng)求頭里加入Authorization,并加上token,這就要用到Axios的請(qǐng)求攔截,并且也用到了它的響應(yīng)攔截,因?yàn)樵诜?wù)端返回401狀態(tài)碼之后應(yīng)要執(zhí)行登出操作,清楚本地token的存儲(chǔ),具體代碼如下:

//request攔截器
instance.interceptors.request.use(
    config => {
        //每次發(fā)送請(qǐng)求之前檢測(cè)本地是否存有token,都要放在請(qǐng)求頭發(fā)送給服務(wù)器
        if(localStorage.getItem("token")){
            if (config.url.indexOf("upload-z0.qiniup.com/putb64") > -1){
                config.headers.Authorization = config.headers["UpToken"];  //加上七牛云上傳token
            }
            else {
                config.headers.Authorization = `token ${localStorage.getItem("token")}`.replace(/(^")|("$)/g, "");  //加上系統(tǒng)接口token
            }
        }
        console.log("config",config)
        return config;
    },
    err => {
        console.log("err",err)
        return Promise.reject(err);
    }
);

//response攔截器
instance.interceptors.response.use(
    response => {
        return response;
    },
    error => { //默認(rèn)除了2XX之外的都是錯(cuò)誤的,就會(huì)走這里
        if(error.response){
            switch(error.response.status){
                case 401:
                    console.log(error.response)
                    store.dispatch("ADMIN_LOGINOUT"); //可能是token過(guò)期,清除它
                    router.replace({ //跳轉(zhuǎn)到登錄頁(yè)面
                        path: "/login",
                        query: { redirect: "/dashboard" } // 將跳轉(zhuǎn)的路由path作為參數(shù),登錄成功后跳轉(zhuǎn)到該路由
                    });
            }
        }
        return Promise.reject(error.response);
    }
);

其中的if else 是因?yàn)楸鞠到y(tǒng)的圖片,音視頻是放在七牛云,上傳需要七牛云上傳base64圖片的時(shí)候token是放在請(qǐng)求頭的,正常的圖片上傳不是放在請(qǐng)求頭,所以這邊對(duì)token做了區(qū)分,如何接入七牛云也會(huì)在下面模塊介紹到。

七牛云接入

本系統(tǒng)的圖片,音視頻是放在七牛云,所以需要接入七牛云。七牛云分了兩種情況,正常圖片和音視頻的上傳和base64圖片的上傳,因?yàn)槠吲T圃趯?duì)他們兩者上傳的Content-Typedomain(域)有所不同,正常圖片和音視頻的Content-Type是headers: {"Content-Type":"multipart/form-data"}domain是domain="https://upload-z0.qiniup.com",而base64圖片的上傳則是headers:{"Content-Type":"application/octet-stream"}domain是domain="https://upload-z0.qiniup.com/putb64/-1",所以他們請(qǐng)求的時(shí)候token放的地方不同,base64就像上面所說(shuō)的放在請(qǐng)求頭Authorization中,而正常的放在form-data中。在服務(wù)端通過(guò)接口請(qǐng)求來(lái)獲取七牛云上傳token,客戶端獲取到七牛云token,通過(guò)不同方案將token帶上。

base64的上傳: headers:{"Content-Type":"application/octet-stream"}domain="https://upload-z0.qiniup.com/putb64/-1",token放在請(qǐng)求頭Authorization中。

正常圖片和音視頻的上傳: headers: {"Content-Type":"multipart/form-data"}domain="https://upload-z0.qiniup.com",token 放在 form-data中。

服務(wù)端通過(guò)qiniu這個(gè)模塊進(jìn)行創(chuàng)建token,服務(wù)端代碼如下:

/**
 * 構(gòu)建一個(gè)七牛云上傳憑證類
 * @class QN
 */
const qiniu = require("qiniu")  //導(dǎo)入qiniu模塊
const config = require("../config")
class QN {
    /**
     * Creates an instance of qn.
     * @param {string} accessKey -七牛云AK
     * @param {string} secretKey -七牛云SK
     * @param {string} bucket -七牛云空間名稱
     * @param {string} origin -七牛云默認(rèn)外鏈域名,(可選參數(shù))
     */
    constructor (accessKey, secretKey, bucket, origin) {
        this.ak = accessKey
        this.sk = secretKey
        this.bucket = bucket
        this.origin = origin
    }
    /**
     * 獲取七牛云文件上傳憑證
     * @param {number} time - 七牛云憑證過(guò)期時(shí)間,以秒為單位,如果為空,默認(rèn)為7200,有效時(shí)間為2小時(shí)
     */
    upToken (time) {
        const mac = new qiniu.auth.digest.Mac(this.ak, this.sk)
        const options = {
            scope: this.bucket,
            expires: time || 7200
        }
        const putPolicy = new qiniu.rs.PutPolicy(options)
        const uploadToken = putPolicy.uploadToken(mac)
        return uploadToken
    }
}

exports.QN = QN;

exports.upToken = () => {
    return new QN(config.qiniu.accessKey, config.qiniu.secretKey, config.qiniu.bucket, config.qiniu.origin).upToken()  //每次調(diào)用都創(chuàng)建一個(gè)token
}
//獲取七牛云token接口
const {upToken} = require("../utils/qiniu")

app.get("/api/uploadToken", (req, res, next) => {
        const token = upToken()
        res.send({
            status: 1,
            message: "上傳憑證獲取成功",
            upToken: token,
        })
    })

由于正常圖片和音視頻的上傳和base64圖片的上傳,因?yàn)槠吲T圃趯?duì)他們兩者上傳的Content-Typedomain(域)有所不同,所以的token請(qǐng)求存放的位置有所不同,因此要區(qū)分,客戶端調(diào)用上傳代碼如下:

//根據(jù)獲取到的上傳憑證uploadToken上傳文件到指定域
    //正常圖片和音視頻的上傳
    uploadFile(formdata, domain="https://upload-z0.qiniup.com",config={headers:{"Content-Type":"multipart/form-data"}}){
        console.log(domain)
        console.log(formdata)
        return instance.post(domain, formdata, config)
    },
    //base64圖片的上傳
    //根據(jù)獲取到的上傳憑證uploadToken上傳base64到指定域
    uploadBase64File(base64, token, domain = "https://upload-z0.qiniup.com/putb64/-1", config = {
        headers: {
            "Content-Type": "application/octet-stream",
        },
    }){
        const pic = base64.split(",")[1];
        config.headers["UpToken"] = `UpToken ${token}`
        return instance.post(domain, pic, config)
    },
function upload(Vue, data, callbackSuccess, callbackFail) {
    //獲取上傳token之后處理
    Vue.prototype.axios.getUploadToken().then(res => {
        if (typeof data === "string"){  //如果是base64
            const token = res.data.upToken
            Vue.prototype.axios.uploadBase64File(data, token).then(res => {
                if (res.status === 200){
                    callbackSuccess && callbackSuccess({
                        data: res.data,
                        result_url: `http://p89inamdb.bkt.clouddn.com/${res.data.key}`
                    })
                }
            }).catch((error) => {
                callbackFail && callbackFail({
                    error
                })
            })
        }
        else if (data instanceof FormData){  //如果是FormData
            data.append("token", res.data.upToken)
            data.append("key", `moment${Date.now()}${Math.floor(Math.random() * 100)}`)
            Vue.prototype.axios.uploadFile(data).then(res => {
                if (res.status === 200){
                    callbackSuccess && callbackSuccess({
                        data: res.data,
                        result_url: `http://p89inamdb.bkt.clouddn.com/${res.data.key}`
                    })
                }
            }).catch((error) => {
                callbackFail && callbackFail({
                    error
                })
            })
        }
        else {
            const formdata = new FormData()  //如果不是formData 就創(chuàng)建formData
            formdata.append("token", res.data.upToken)
            formdata.append("file", data.file || data)
            formdata.append("key", `moment${Date.now()}${Math.floor(Math.random() * 100)}.${data.file.type.split("/")[1]}`)
            // 獲取到憑證之后再將文件上傳到七牛云空間
            console.log("formdata",formdata)
            Vue.prototype.axios.uploadFile(formdata).then(res => {
                console.log("res",res)
                if (res.status === 200){
                    callbackSuccess && callbackSuccess({
                        data: res.data,
                        result_url: `http://p89inamdb.bkt.clouddn.com/${res.data.key}` //返回的圖片鏈接
                    })
                }
            }).catch((error) => {
                console.log(error)
                callbackFail && callbackFail({
                    error
                })
            })
        }

    })
}

export default upload
路由權(quán)限模塊

系統(tǒng)的后臺(tái)管理面向的是合作作者和管理員,涉及到兩種角色,故此要做權(quán)限管理。不同的權(quán)限對(duì)應(yīng)著不同的路由,同時(shí)側(cè)邊欄的菜單也需根據(jù)不同的權(quán)限,異步生成,不同于以往的服務(wù)端直接返回路由表,由前端動(dòng)態(tài)生成,接下來(lái)介紹下登錄和權(quán)限驗(yàn)證的思路:

登錄:當(dāng)用戶填寫(xiě)完賬號(hào)和密碼后向服務(wù)端驗(yàn)證是否正確,驗(yàn)證通過(guò)之后,服務(wù)端會(huì)返回一個(gè)token,拿到token之后前端會(huì)根據(jù)token再去拉取一個(gè)getAdminInfo的接口來(lái)獲取用戶的詳細(xì)信息(如用戶權(quán)限,用戶名等等信息)。

權(quán)限驗(yàn)證:通過(guò)token獲取用戶對(duì)應(yīng)的role,動(dòng)態(tài)根據(jù)用戶的role算出其對(duì)應(yīng)有權(quán)限的路由,通過(guò)vue-router的beforeEach進(jìn)行全局前置守衛(wèi)再通過(guò)router.addRoutes動(dòng)態(tài)掛載這些路由。

代碼有點(diǎn)多,這邊就直接放流程圖哈~~


權(quán)限路由流程圖

最近正好也在公司做中后臺(tái)項(xiàng)目,公司的中后臺(tái)項(xiàng)目的這邊是由服務(wù)端生成路由表,前端進(jìn)行直接渲染,畢竟公司的一整套業(yè)務(wù)比較成熟。但是我們會(huì)在想能不能由前端維護(hù)路由表,這樣不用到時(shí)候項(xiàng)目迭代,前端每增加頁(yè)面都要讓服務(wù)端兄弟配一下路由和權(quán)限,當(dāng)然前提可能是項(xiàng)目比較小的時(shí)候。

賬號(hào)模塊

賬號(hào)模塊是業(yè)務(wù)中最為基礎(chǔ)的模塊,承擔(dān)著整個(gè)系統(tǒng)所有的賬號(hào)相關(guān)的功能。系統(tǒng)實(shí)現(xiàn)了用戶注冊(cè)、用戶登錄、密碼修改、找回密碼功能。

系統(tǒng)的賬號(hào)模塊使用了郵件服務(wù),針對(duì)普通用戶的注冊(cè)采用了郵件服務(wù)來(lái)發(fā)送驗(yàn)證碼,以及密碼的修改等操作都采用了郵件服務(wù)。在node.js中主要采用了Nodemailer,Nodemailer是一個(gè)簡(jiǎn)單易用的Node.js郵件發(fā)送組件,它的使用可以摸我摸我摸我,通過(guò)此模塊進(jìn)行郵件的發(fā)送。你們可能會(huì)問(wèn),為什么不用短信服務(wù)呢?哈~因?yàn)槎绦欧?wù)要錢(qián),哈哈哈

/*
* email 郵件模塊
*/

const nodemailer = require("nodemailer");
const smtpTransport = require("nodemailer-smtp-transport");
const config = require("../config")

const transporter = nodemailer.createTransport(smtpTransport({
    host: "smtp.qq.com",
    secure: true,
    port: 465,  // SMTP 端口
    auth: {
        user: config.email.account,
        pass: config.email.password  //這里密碼不是qq密碼,是你設(shè)置的smtp授權(quán)碼
    }
}));

let clientIsValid = false;
const verifyClient = () => {
    transporter.verify((error, success) => {
        if (error) {
            clientIsValid = false;
            console.warn("郵件客戶端初始化連接失敗,將在一小時(shí)后重試");
            setTimeout(verifyClient, 1000 * 60 * 60);
        } else {
            clientIsValid = true;
            console.log("郵件客戶端初始化連接成功,隨時(shí)可發(fā)送郵件");
        }
    });
};
verifyClient();

const sendMail = mailOptions => {
    if (!clientIsValid) {
        console.warn("由于未初始化成功,郵件客戶端發(fā)送被拒絕");
        return false;
    }
    mailOptions.from = ""ShineTomorrow" "
    transporter.sendMail(mailOptions, (error, info) => {
        if (error) return console.warn("郵件發(fā)送失敗", error);
        console.log("郵件發(fā)送成功", info.messageId, info.response);
    });
};

exports.sendMail = sendMail;

賬號(hào)的注冊(cè)先是填寫(xiě)email,填寫(xiě)好郵箱之后會(huì)通過(guò)Nodemailer發(fā)送一封含有有效期的驗(yàn)證碼郵件,之后填寫(xiě)驗(yàn)證碼、昵稱和密碼即可完成注冊(cè),并且為了安全考慮,對(duì)密碼采用了安全哈希算法(Secure Hash Algorithm)進(jìn)行加密。賬號(hào)的登錄以賬號(hào)或者郵箱號(hào)加上密碼進(jìn)行登錄,并且采用上文所說(shuō)的JSON Web Token(JWT)身份認(rèn)證機(jī)制,從而實(shí)現(xiàn)用戶和用戶登錄狀態(tài)數(shù)據(jù)的對(duì)應(yīng)。


我的郵件長(zhǎng)這樣

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/97123.html

相關(guān)文章

  • 聊聊畢業(yè)設(shè)計(jì)系列 --- 項(xiàng)目介紹

    摘要:又將整個(gè)文藝類閱讀系統(tǒng)的業(yè)務(wù)劃分為兩大部分,分別是面向管理員和合作作者的后臺(tái)管理系統(tǒng)和面向用戶的移動(dòng)端,系統(tǒng)的需求分析將圍繞這兩部分進(jìn)行展開(kāi)。 效果展示 showImg(https://user-gold-cdn.xitu.io/2018/8/26/16576a709bd02f5f?w=1409&h=521&f=gif&s=30128195); showImg(https://user...

    Pink 評(píng)論0 收藏0
  • 聊聊畢業(yè)設(shè)計(jì)系列 --- 項(xiàng)目介紹

    摘要:又將整個(gè)文藝類閱讀系統(tǒng)的業(yè)務(wù)劃分為兩大部分,分別是面向管理員和合作作者的后臺(tái)管理系統(tǒng)和面向用戶的移動(dòng)端,系統(tǒng)的需求分析將圍繞這兩部分進(jìn)行展開(kāi)。 效果展示 showImg(https://user-gold-cdn.xitu.io/2018/8/26/16576a709bd02f5f?w=1409&h=521&f=gif&s=30128195); showImg(https://user...

    villainhr 評(píng)論0 收藏0
  • 聊聊畢業(yè)設(shè)計(jì)系列 --- 系統(tǒng)實(shí)現(xiàn)

    摘要:七牛云接入本系統(tǒng)的圖片,音視頻是放在七牛云,所以需要接入七牛云。在服務(wù)端通過(guò)接口請(qǐng)求來(lái)獲取七牛云上傳,客戶端獲取到七牛云,通過(guò)不同方案將帶上。 效果展示 showImg(https://user-gold-cdn.xitu.io/2018/8/26/16576a709bd02f5f?w=1409&h=521&f=gif&s=30128195); showImg(https://user...

    qpal 評(píng)論0 收藏0
  • php資料集

    摘要:簡(jiǎn)單字符串緩存實(shí)戰(zhàn)完整實(shí)戰(zhàn)種設(shè)計(jì)模式設(shè)計(jì)模式是面向?qū)ο蟮淖罴褜?shí)踐成為專業(yè)程序員路上用到的各種優(yōu)秀資料神器及框架成為一名專業(yè)程序員的道路上,需要堅(jiān)持練習(xí)學(xué)習(xí)與積累,技術(shù)方面既要有一定的廣度,更要有自己的深度。 微型新聞系統(tǒng)的開(kāi)發(fā)(PHP 5.4 + MySQL 5.5) 微型新聞系統(tǒng)的開(kāi)發(fā)(PHP 5.4 + MySQL 5.5) 九個(gè)很有用的 PHP 代碼 php 代碼 國(guó)內(nèi)值得關(guān)注的...

    RobinQu 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<