# url handlers import re, time, json, logging, hashlib, base64, asyncio ## markdown 是处理日志文本的一种格式语法 import markdown2 from aiohttp import web from coroweb import get, post ## 分页管理以及调取API时的错误信息 from apis import Page, APIValueError, APIResourceNotFoundError,APIError from models import User, Comment, Blog, next_id from config import configs COOKIE_NAME = 'awesession' _COOKIE_KEY = configs.session.secret def user2cookie(user, max_age): # build cookie string by: id-expires-sha1 expires = str(int(time.time() + max_age)) s = '%s-%s-%s-%s' % (user.id, user.passwd, expires, _COOKIE_KEY) L = [str(user.id), expires, hashlib.sha1(s.encode('utf-8')).hexdigest()] return '-'.join(L) @get('/') async def index(request): # users = await User.findAll() summary = 'XXXXXXXXX啦啦啦啦啦啦啦' blogs = [ Blog(id='1', name='AAAAA', summary=summary, created_at=time.time() - 1200), Blog(id='2', name='BBBBB', summary=summary, created_at=time.time() - 3600), Blog(id='3', name='CCCCC', summary=summary, created_at=time.time() - 7200) ] return { '__template__': 'blogs.html', 'blogs': blogs, # '__user__': request.__user__ } @get('/api/users') async def api_get_users(): users = await User.findAll(orderBy='created_at desc') for u in users: u.passwd = '******' return dict(users=users) @get('/register') def register(): return { '__template__': 'register.html' } ## 处理登录页面URL @get('/signin') def signin(): return { '__template__': 'signin.html' } @get('/signout') def signout(request): referer = request.headers.get('Referer') r = web.HTTPFound(referer or '/') r.set_cookie(COOKIE_NAME, '-deleted-', max_age=0, httponly=True) logging.info('user signed out.') return r ## 用户登录验证API @post('/api/authenticate') async def authenticate(*, email, passwd): if not email: raise APIValueError('email', 'Invalid email.') if not passwd: raise APIValueError('passwd', 'Invalid password.') users = await User.findAll('email=?', [email]) if len(users) == 0: raise APIValueError('email', 'Email not exist.') user = users[0] # check passwd: sha1 = hashlib.sha1() sha1.update(user.id.encode('utf-8')) #AttributeError: 'int' object has no attribute 'encode' sha1.update(b':') sha1.update(passwd.encode('utf-8')) # if user.passwd != sha1.hexdigest(): # raise APIValueError('passwd', 'Invalid password.') # authenticate ok, set cookie: r = web.Response() r.set_cookie(COOKIE_NAME, user2cookie(user, 86400), max_age=86400, httponly=True) user.passwd = '******' r.content_type = 'application/json' r.body = json.dumps(user, ensure_ascii=False).encode('utf-8') return r _RE_EMAIL = re.compile(r'^[a-z0-9\.\-\_]+\@[a-z0-9\-\_]+(\.[a-z0-9\-\_]+){1,4}$') _RE_SHA1 = re.compile(r'^[0-9a-f]{40}$') ## 用户注册API @post('/api/users') async def api_register_user(*, email, name, passwd): if not name or not name.strip(): raise APIValueError('name') if not email or not _RE_EMAIL.match(email): raise APIValueError('email') if not passwd or not _RE_SHA1.match(passwd): raise APIValueError('passwd') users = await User.findAll('email=?', [email]) if len(users) > 0: raise APIError('register:failed', 'email', 'Email is already in use.') uid = next_id() sha1_passwd = '%s:%s' % (uid, passwd) user = User(id=uid, name=name.strip(), email=email, passwd=hashlib.sha1(sha1_passwd.encode('utf-8')).hexdigest(), image='http://www.gravatar.com/avatar/%s?d=mm&s=120' % hashlib.md5(email.encode('utf-8')).hexdigest()) await user.save() # make session cookie: r = web.Response() r.set_cookie(COOKIE_NAME, user2cookie(user, 86400), max_age=86400, httponly=True) user.passwd = '******' r.content_type = 'application/json' r.body = json.dumps(user, ensure_ascii=False).encode('utf-8') return r # 解密cookie: @asyncio.coroutine def cookie2user(cookie_str): ''' Parse cookie and load user if cookie is valid. ''' if not cookie_str: return None try: L = cookie_str.split('-') if len(L) != 3: return None uid, expires, sha1 = L if int(expires) < time.time(): return None user = yield from User.find(uid) if user is None: return None s = '%s-%s-%s-%s' % (uid, user.passwd, expires, _COOKIE_KEY) if sha1 != hashlib.sha1(s.encode('utf-8')).hexdigest(): logging.info('invalid sha1') return None user.passwd = '******' return user except Exception as e: logging.exception(e) return None @asyncio.coroutine def auth_factory(app, handler): @asyncio.coroutine def auth(request): logging.info('check user: %s %s' % (request.method, request.path)) request.__user__ = None cookie_str = request.cookies.get(COOKIE_NAME) if cookie_str: user = yield from cookie2user(cookie_str) if user: logging.info('set current user: %s' % user.email) request.__user__ = user return (yield from handler(request)) return auth