天天看點

【軟軟軟-技術部落格】使用郵箱驗證并激活賬戶

為什麼需要使用郵箱驗證賬戶?

我們的項目的特殊之處在于,是通過向使用者郵箱發送郵件的方式來實作DDL的提醒的,是以需要確定使用者的郵箱是正确的,如果注冊時使用的郵箱是錯誤的,不僅會導緻使用者收不到DDL提醒郵件,也會打擾到别人。

此外,我們選擇使用北航郵箱進行驗證,這樣做還有一個好處在于,北航郵箱是綁定學号的,即可以直接使用“學号@buaa.edu.cn”的格式來發送郵件。這樣在建立賬戶時,可以確定使用者輸入的是自己的學号,而不能冒名頂替使用他人的學号注冊。

技術原理

1. 在資料庫中為User增加is_active字段

為了實作沒有完成郵箱驗證的使用者不能登陸,我們在資料庫中的User實體中添加了is_active字段,以辨別使用者好是否激活,并在使用者登入時檢查賬戶是否激活,如果未激活就不能登陸。在使用者完成郵箱驗證後,将該使用者的is_active字段設定為True(已激活)。

class User(models.Model):
    '''
    Other attributes...
    '''
    is_active = models.BooleanField(default=False)   
           

2. 生成激活連結并發送激活郵件

為了給每個使用者生成其獨立的激活連結,我們建立了一個Token類,通過itsdangerous中的URLSafeTimedSerializer類來生成和驗證Token。調用Token類,使用使用者的uid+SECRET_KEY結合生成token,并将這個token加入激活連結的url部分。

class Token():
    def __init__(self, security_key):
        self.security_key = security_key
        self.salt = base64.b64encode(security_key.encode(encoding='utf-8'))

    def generate_validate_token(self, username):
        serializer = utsr(self.security_key)
        return serializer.dumps(username, self.salt)

    def confirm_validate_token(self, token, expiration=3600):
        serializer = utsr(self.security_key)
        return serializer.loads(token, salt=self.salt, max_age=expiration)
           
def create_user(request): # 使用者注冊
    '''
    Other codes...
    '''
		token_confirm = Token(settings.SECRET_KEY)
		token = token_confirm.generate_validate_token(data["uid"]) # 根據uid生成token
  	message = "\n".join([
            u'親愛的 {0} {1}, 歡迎使用ddl_killer'.format(data["uid"], data['username']),
            u'請通路該連結,完成使用者驗證: <a href="http://123.57.67.161:8000/api/activate/?							token={0}">ddl_killer 注冊連結</a>'.format(token),
            u'ddl_killer 團隊緻上.'])
           

在發送郵件部分,我們使用了yagmail來發送郵件。

# 四個參數從左到右分别是:收件郵箱位址,郵件标題,郵件内容,附件
settings.YAG.send([data['email']], u'ddl_killer 注冊使用者驗證資訊', message, None)
           

3. 響應激活連結并激活使用者

在Django後端收到激活連結格式的url請求時,将進入active_user視圖,完成使用者的激活。

def active_user(request): 
    token = request.GET['token']
    token_confirm = Token(settings.SECRET_KEY)
    try:
        uid = token_confirm.confirm_validate_token(token)
        print(uid)
    except:
        return HttpResponse(u'對不起,驗證連結已經過期')
    try:
        user = User.objects.get(uid=uid)
    except User.DoesNotExist:
        return HttpResponse(u'對不起,您所驗證的使用者不存在,請重新注冊')
    user.is_active = True
    user.save()
    confirm = u'驗證成功,請進行登入操作。'
    return HttpResponseRedirect('/', {'msg':confirm}) # 重定向回登陸頁面
           

其他應用

了解郵箱驗證的原理之後,就可以使用郵箱+token的組合完成許多其他功能了,例如:

  1. 忘記密碼時,可以通過向北航郵箱發送郵件的方式重設密碼;
  2. 使用者更改提醒郵箱時,需要向新郵箱發送郵件确認。