為什麼需要使用郵箱驗證賬戶?
我們的項目的特殊之處在于,是通過向使用者郵箱發送郵件的方式來實作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的組合完成許多其他功能了,例如:
- 忘記密碼時,可以通過向北航郵箱發送郵件的方式重設密碼;
- 使用者更改提醒郵箱時,需要向新郵箱發送郵件确認。