国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

用Python實現web端用戶登錄和注冊功能的教程

2019-11-25 17:35:36
字體:
來源:轉載
供稿:網友

用戶管理是絕大部分Web網站都需要解決的問題。用戶管理涉及到用戶注冊和登錄。

用戶注冊相對簡單,我們可以先通過API把用戶注冊這個功能實現了:

_RE_MD5 = re.compile(r'^[0-9a-f]{32}$')@api@post('/api/users')def register_user(): i = ctx.request.input(name='', email='', password='') name = i.name.strip() email = i.email.strip().lower() password = i.password if not name:  raise APIValueError('name') if not email or not _RE_EMAIL.match(email):  raise APIValueError('email') if not password or not _RE_MD5.match(password):  raise APIValueError('password') user = User.find_first('where email=?', email) if user:  raise APIError('register:failed', 'email', 'Email is already in use.') user = User(name=name, email=email, password=password, image='http://www.gravatar.com/avatar/%s?d=mm&s=120' % hashlib.md5(email).hexdigest()) user.insert() return user

注意用戶口令是客戶端傳遞的經過MD5計算后的32位Hash字符串,所以服務器端并不知道用戶的原始口令。

接下來可以創建一個注冊頁面,讓用戶填寫注冊表單,然后,提交數據到注冊用戶的API:

{% extends '__base__.html' %}{% block title %}注冊{% endblock %}{% block beforehead %}<script>function check_form() { $('#password').val(CryptoJS.MD5($('#password1').val()).toString()); return true;}</script>{% endblock %}{% block content %}<div class="uk-width-2-3"> <h1>歡迎注冊!</h1> <form id="form-register" class="uk-form uk-form-stacked" onsubmit="return check_form()">  <div class="uk-alert uk-alert-danger uk-hidden"></div>  <div class="uk-form-row">   <label class="uk-form-label">名字:</label>   <div class="uk-form-controls">    <input name="name" type="text" class="uk-width-1-1">   </div>  </div>  <div class="uk-form-row">   <label class="uk-form-label">電子郵件:</label>   <div class="uk-form-controls">    <input name="email" type="text" class="uk-width-1-1">   </div>  </div>  <div class="uk-form-row">   <label class="uk-form-label">輸入口令:</label>   <div class="uk-form-controls">    <input id="password1" type="password" class="uk-width-1-1">    <input id="password" name="password" type="hidden">   </div>  </div>  <div class="uk-form-row">   <label class="uk-form-label">重復口令:</label>   <div class="uk-form-controls">    <input name="password2" type="password" maxlength="50" placeholder="重復口令" class="uk-width-1-1">   </div>  </div>  <div class="uk-form-row">   <button type="submit" class="uk-button uk-button-primary"><i class="uk-icon-user"></i> 注冊</button>  </div> </form></div>{% endblock %}Try

這樣我們就把用戶注冊的功能完成了:

2015430102634859.jpg (560×753)

用戶登錄比用戶注冊復雜。由于HTTP協議是一種無狀態協議,而服務器要跟蹤用戶狀態,就只能通過cookie實現。大多數Web框架提供了Session功能來封裝保存用戶狀態的cookie。

Session的優點是簡單易用,可以直接從Session中取出用戶登錄信息。

Session的缺點是服務器需要在內存中維護一個映射表來存儲用戶登錄信息,如果有兩臺以上服務器,就需要對Session做集群,因此,使用Session的Web App很難擴展。

我們采用直接讀取cookie的方式來驗證用戶登錄,每次用戶訪問任意URL,都會對cookie進行驗證,這種方式的好處是保證服務器處理任意的URL都是無狀態的,可以擴展到多臺服務器。

由于登錄成功后是由服務器生成一個cookie發送給瀏覽器,所以,要保證這個cookie不會被客戶端偽造出來。

實現防偽造cookie的關鍵是通過一個單向算法(例如MD5),舉例如下:

當用戶輸入了正確的口令登錄成功后,服務器可以從數據庫取到用戶的id,并按照如下方式計算出一個字符串:

"用戶id" + "過期時間" + MD5("用戶id" + "用戶口令" + "過期時間" + "SecretKey")

當瀏覽器發送cookie到服務器端后,服務器可以拿到的信息包括:

  •     用戶id
  •     過期時間
  •     MD5值

如果未到過期時間,服務器就根據用戶id查找用戶口令,并計算:

MD5("用戶id" + "用戶口令" + "過期時間" + "SecretKey")

并與瀏覽器cookie中的MD5進行比較,如果相等,則說明用戶已登錄,否則,cookie就是偽造的。

這個算法的關鍵在于MD5是一種單向算法,即可以通過原始字符串計算出MD5,但無法通過MD5反推出原始字符串。

所以登錄API可以實現如下:

@api@post('/api/authenticate')def authenticate():  i = ctx.request.input()  email = i.email.strip().lower()  password = i.password  user = User.find_first('where email=?', email)  if user is None:    raise APIError('auth:failed', 'email', 'Invalid email.')  elif user.password != password:    raise APIError('auth:failed', 'password', 'Invalid password.')  max_age = 604800  cookie = make_signed_cookie(user.id, user.password, max_age)  ctx.response.set_cookie(_COOKIE_NAME, cookie, max_age=max_age)  user.password = '******'  return user# 計算加密cookie:def make_signed_cookie(id, password, max_age):  expires = str(int(time.time() + max_age))  L = [id, expires, hashlib.md5('%s-%s-%s-%s' % (id, password, expires, _COOKIE_KEY)).hexdigest()]  return '-'.join(L)對于每個URL處理函數,如果我們都去寫解析cookie的代碼,那會導致代碼重復很多次。利用攔截器在處理URL之前,把cookie解析出來,并將登錄用戶綁定到ctx.request對象上,這樣,后續的URL處理函數就可以直接拿到登錄用戶:@interceptor('/')def user_interceptor(next):  user = None  cookie = ctx.request.cookies.get(_COOKIE_NAME)  if cookie:    user = parse_signed_cookie(cookie)  ctx.request.user = user  return next()# 解密cookie:def parse_signed_cookie(cookie_str):  try:    L = cookie_str.split('-')    if len(L) != 3:      return None    id, expires, md5 = L    if int(expires) < time.time():      return None    user = User.get(id)    if user is None:      return None    if md5 != hashlib.md5('%s-%s-%s-%s' % (id, user.password, expires, _COOKIE_KEY)).hexdigest():      return None    return user  except:    return NoneTry

這樣,我們就完成了用戶注冊和登錄的功能。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 广平县| 克拉玛依市| 大洼县| 乌苏市| 巢湖市| 永登县| 含山县| 乐山市| 安丘市| 惠东县| 连山| 凉城县| 延津县| 芦溪县| 弥渡县| 边坝县| 集贤县| 兖州市| 辛集市| 容城县| 阿克| 满洲里市| 宜阳县| 冷水江市| 门源| 收藏| 沙河市| 青海省| 定襄县| 纳雍县| 石楼县| 沈阳市| 景德镇市| 饶平县| 平远县| 荆州市| 通许县| 新沂市| 浦城县| 珠海市| 崇信县|