【前端】Popush前端架构分析&注册后自动登录的实现

       通过阅读Popush前端代码,又可以加深对backbone以及socket.io的认识。感谢队友配置好了Linux下的环境,终于可以成功运行了。

      和注册登录相关的代码主要有以下几个部分。在register-view.js中,有

<pre name="code" class="html">/*注册视图*/
var app = app || {};
(function () {
    'use strict';
    app.RegisterView = Backbone.View.extend({
        el: '#register',
        events: {
            'keypress #register-inputName': 'registerOnEnter',
            'keypress #register-inputPassword': 'registerOnEnter',
            'keypress #register-confirmPassword': 'registerOnEnter',
            'click #register-submit': 'register',
        },
        register: function () {
            var name = $('#register-inputName').val(),
			in_pw1 = $('#register-inputPassword'),
			in_pw2 = $('#register-confirmPassword');
            var pass = in_pw1.val();
            var confirm = in_pw2.val();
            in_pw1.val('');
            in_pw2.val('');
            var id = '#register-message',
			str = '';
            if (!/^[A-Za-z0-9]*$/.test(name)) {
                str = 'name invalid';
            } else if (name.length < 6 || name.length > 20) {
                str = 'namelength';
            } else if (pass.length > 31) {
                str = 'passlength';
            } else if (pass != confirm) {
                str = 'doesntmatch';
            }
            if (str) {
                app.showMessageBar(id, str);
            } else if (app.Lock.attach({
				loading: '#register-control',
				error: function (data) {
					app.showMessageBar(id, data.err, 'error');
				},
                success: function () {
					app.showMessageBar(id, 'registerok');
				},
            })) {
                app.socket.emit('register', {
                    name: name,
                    password: pass,
                });
            }
        },
        /*快捷键回车注册*/
        registerOnEnter: function (e) {
            if (e.which == 13) {
                this.register();
            }
        },
        show: function () {
            $('#register-inputPassword').val('');
            $('#register-confirmPassword').val('');
            $('#register-message').hide();
            $('#register-padding').slideDown('fast');
            $('#register-inputName').focus();
        },
    });
    app.init || (app.init = {});
    app.init.registerView = function () {
        if (app.views['register']) {
            return;
        }
        app.views['register'] = new app.RegisterView();
    };
})();

 
 

        可以看到,当接收到“注册“的信息(由enter键或点击窗口的”注册“键触发)后,程序会发送”register'的信号。由app.js中的函数来接受socket的信号:

	socket.on('register', function(data) { // name, password
		if(!check(data, 'name', 'password')){
			return;
		}
		userDAO.register(data.name, data.password, data.avatar || 'images/character.png', 'user', function(err){
			socket.emit('register', {err:err});
		});
	});

        也就是接收信号,将data存储到数据库中。这里的userDAO.register干的就是将接收到的信息存储到数据库中的工作。至于userDAO,看到下方的源代码可以更清楚地看到数据库做了什么。

        因为我们想要实现注册后自动登录,所以这里关心的是它要在哪里完成了验证注册,之后又触发了什么事件。注册登录,其实只需要在看到它正常验证,将信息储存到数据库中,然后用该注册信息进行登录就可以了。下方是models里对于数据库交互的部分,其中的md5是一种加密函数。

/models/userDAO.js

UserDAO.prototype.register = function(name, password, avatar, group, callback){
	
	if(!validateName(name)){
		return callback("name invalid");
	}

	if(password.length > 32){
		return callback("password too long");
	}

	lock.acquire(name, function(){
		db.user.findOne({name:name}, {_id:1}, function(err, user){
			if(err){
				lock.release(name);
				return callback("inner error");
			}
			if(user){
				lock.release(name);
				return callback("name exists");
			}
			db.user.insert({
				name:name,
				password:md5(xor(md5(name), md5(password))),
				avatar:avatar,
				state:"normal",
				group:group,
				docs:[],
				createTime: new Date().getTime()
			}, 
			function(err, newUser){
				if(err){
					lock.release(name);
					return callback("inner error");
				}
				else if(!newUser){
					lock.release(name);
					return callback("inner error");
				}
				else{
					lock.release(name);
					return callback(null);
				}
			});
		});
	});
};

UserDAO.prototype.login = function(name, password, ip, callback){
	var that = this;
	db.user.findOne({name:name}, function(err, user){
		if(err){
			return callback("inner error");
		}
		if(!user){
			return callback("unauthorized");
		}
		if(md5(xor(md5(name), md5(password))) == user.password){
			delete user.password;
			db.user.update({_id:user._id}, {
				$set:{
					loginTime:new Date().getTime(),
					loginIP:ip
				}
			}, function(err){
				if(err){
					return callback("inner error");
				}
				db.doc.find({_id : {$in:user.docs}}, {revisions:0,_id:0}, function(err, docs){
					if (err){
						return callback("inner error");
					}
					if (docs.length == 0){
						docs = [];
						user.docs = docs;
						return callback(null,user);
					}
					else{
						var counter = 0;
						function t(doc){
							db.user.findOne({_id:doc.owner},{name:1,_id:0,avatar:1},function(err,trueowner){
								if (err){
									that.innerError = true;
								}
								doc.owner = trueowner;
								db.user.find({_id:{$in:doc.members}},{name:1,_id:0,avatar:1},function(err,members){
									if (err){
										that.innerError = true;
									}
									doc.members = members;
									counter++;
									if (counter == docs.length){
										user.docs = docs;
										return callback(null ,user);
									}
								});
							});
						}
						for (i in docs){
							if (that.innerError){
								that.innerError = false;
								return callback("inner error");
							}
							t(docs[i]);
						}
					}
				});
			});
		}else{
			return callback("unauthorized");
		}
	});
};


        因此,问题的关键就在于 register-view.js中的这一部分代码:

else if(app.Lock.attach({
			loading: '#register-control',
			error: function (data) {
				app.showMessageBar(id, data.err, 'error');
			},
                        success: function () {
				app.showMessageBar(id, 'registerok');
			},
           })) {
       app.socket.emit('register', {
              name: name,
              password: pass,
       });

        也就是说,当它发送注册信息之后,如果失败了,就会显示MessageBar(id, data.err, 'error'),对应过去找这个函数可以看到有哪些错误。而如果成功了,就可以显示成功的message bar——app.showMessageBar(id, 'registerok');

        我的想法很简单,只要将app.showMessageBar(id, 'registerofk')改为发送登录信息就可以了。修改之后的代码如下:

 else if (app.Lock.attach({
		loading: '#register-control',
		error: function (data) {
			app.showMessageBar(id, data.err, 'error');
		},
                success: function () {
	<span style="white-space:pre">	</span>    //register is ok
                    app.socket.emit('login', {
                        name: name,
                        password: pass,
                     });
		},
            })) {
                app.socket.emit('register', {
                    name: name,
                    password: pass,
                });
            }

        尝试一下,基础的注册后自动登录就完成了。但是这样还会有一个小小的问题——效率。这样的效率并不是最优的,因为我们知道在login的时候,其实是还有一步验证检查的。下面的一段代码来自于static/app.js。第一句的if(!check(data, 'name', 'password')就是对姓名和密码进行核对。

        由于是刚刚注册过,其实是不需要这样的核对的。

socket.on('login', function(data){ // name, password
		if(!check(data, 'name', 'password')){
			return;
		}
		userDAO.login(data.name, data.password, ip, function(err, user){
			if(err){
				return socket.emit('login', {err:err});
			}
			var sid;
			while(sid = crypto.randomBytes(32).toString('base64')){
				if(!session[sid])
					break;
			}
			socket.session = session[sid] = {user:user, sid:sid};
			if(users[user.name]){
				delete session[users[user.name].session.sid];
				delete users[user.name].session;
				users[user.name].emit('unauthorized');
			}
			users[user.name] = socket;
			socket.emit('login', socket.session);
		});
	});

        在之后可以再尝试进行优化。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值