登录就是检验数据库是否存在用户信息并返回,需要使用cookie与session。
首先还是需要理解一下cookie与session。简单说,Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。
cookie是服务器将信息放在你的浏览器中,你每次访问服务器都要带着这个cookie。如果只使用cookie进行验证,就需要将用户名等信息存储到cookie里,服务器就能知道你是谁,从而保持会话,但是不安全。
session可以借助cookie(也可以不借助,使用url重写技术,可以将session id写在URL中返回给服务器),主要存放信息的地方是在服务器端,给浏览器一个session id标识,浏览器带着这个标识去服务器端验证自己,如果服务器有它的session就检索出来并使用,如果没有,则新建一个。
cookie 和session 的区别:
1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗
考虑到安全应当使用session。
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
考虑到减轻服务器性能方面,应当使用COOKIE。
4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
还是使用session比较好。
具体来说登录功能的实现
点击登录,输入用户名密码,post到后端,后端查找数据库,存在则建立session(req.session.user=doc即可),后端返回用户信息(包括昵称、头像地址……),前端渲染。但是需要在app.js文件中提前做一些配置,也就是express-session中间件的使用方法。
首先引入express-session,使用如下,这里需要注意的是原来session的默认存储是在服务器内存中,但是生产环境中这样很容易造成内存泄漏,所以这里就直接将session存储到数据库里了。
var MongoStore = require('connect-mongo')(session)//注意存储到mongodb需要引入这个插件
// 使用 session 中间件
app.use(session({
name: 'identityKey',//保存到浏览器端的sessionid的别名
secret : 'secret', // 对session id 相关的cookie 进行签名
resave : false,
store: new MongoStore({
db: 'sessiondb',
url: 'mongodb://127.0.0.1:27017/sessiondb'
}),//将session存储到数据库中,防止服务器挂了之后session信息找不到。默认session是内存存储(服务器端) */
saveUninitialized: false, // 是否保存未初始化的会话
cookie : {
maxAge : 1000 * 60 * 60 , // 设置 session 的有效时间1h,单位毫秒,到时间之后会删除浏览器cookie以及服务器session
},
}));
在路由文件中写如下:
router.post("/login",function(req,res,next){
var param = {
userName:req.body.userName,
userPwd:req.body.userPwd
}
User.findOne(param,(err,doc)=>{
if(err){
res.json({
status:"1",
msg:err.message
})
}else{
//存在用户信息
if(doc){
req.session.user = doc;//一句话即可建立session并将sessionid发送到浏览器端
res.json({
status:'0',
msg:'suc',
result:{
nickName:doc.userNickName,
userHeadImg:doc.userHeadImg
} //返回用户的昵称和头像
});
}else{ //不存在用户信息
res.json({
status:'1',
msg:'账号密码错误',
result:''
});
}
}
})
});
前端方面,登录成功后将vuex全局变量globalNickName设为后端返回的nickName值,根据这个值存在与否决定导航栏是否显示个人信息栏或是注册登录栏(v-if=“globalNickName”)。但是在刷新网页或是重新进入这个网址后发现vuex的全局变量又没了,所以需要一个checkLogin函数(每次一打开网页就要调用,所以在mounted函数中调用),与后端交互,根据是否存在session来判断是否给全局变量globalNickName赋值,赋值之后理所当然个人信息栏就会出来。
//前端代码
checkLogin(){
axios.get("/users/checkLogin").then((response)=>{
var res = response.data;
if(res.status=="0"){
this.$store.commit("updateUserInfo",res.result);
}
});
},
//后端代码
router.get("/checkLogin", (req,res,next)=> {
if(req.session.user){
res.json({
status:'0',
msg:'',
result:req.session.user.userNickName
});
}else{
res.json({
status:'1',
msg:'未登录',
result:''
});
}
});
关于vuex的使用方法,在main.js中写如下代码
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
globalNickName:''
},
mutations: {
updateUserInfo(state, nickName) {
state.globalNickName = nickName;
}
}
});
new Vue({
el: '#app',
store, //这里需要引用
router,
components: { App },
template: '<App/>'
})
以后在各个文件中写如下代码即可改变全局变量
import { mapState } from 'vuex'
computed:{
...mapState(['globalNickName'])
},
this.$store.commit("updateUserInfo",xxx);
之后是登出功能,登出需要将服务器端的session和浏览器端的cookie一并清除,前端将globalNickname变量置空,这样就会重新显现出注册登录栏。
//后端登出接口
router.post("/logout", (req,res,next) => {
req.session.destroy()
res.cookie('identityKey','',{
maxAge:-1
})
res.json({
status:"0",
msg:'已登出',
})
//前端登出
logOut(){
axios.post("/users/logout").then((response)=>{
let res = response.data;
if(res.status=="0"){
this.$store.commit("updateUserInfo",'');
}
})
},
需要注意的就是session和cookie是存放在两个地方的东西,一个在服务器一个在浏览器。
至此登录功能结束!