在PostgreSQL下实现用户认证

问题

如何利用PostgreSQL数据库实现一个用户认证系统?

方案

用户认证系统有很多功能。在这个例子中,将展示如何在PostgreSQL数据库环境下一步一步完成一个用户认证系统

必需

因为要用到 mako 模板和postgreSQL数据库,所以要:

  1. import web
  2. from web.contrib.template import render_mako
  3. import pg

第一步:创建数据库

首先,为创建一个用户表。虽然这个表结构非常简单,但对于大部分项目来说都足够用了。

  1. CREATE TABLE example_users (
  2. id serial NOT NULL,
  3. user character varying(80) NOT NULL,
  4. pass character varying(80) NOT NULL,
  5. email character varying(100) NOT NULL,
  6. privilege integer NOT NULL DEFAULT 0,
  7. CONSTRAINT utilisateur_pkey PRIMARY KEY (id)
  8. )

第二步:确定网址

登录和注销对应两个网址:

  • “Login” 对应登录页
  • “Reset” 对应注销页

urls = ( ‘/login’, ‘login’, ‘/reset’, ‘reset’, )

第三步:判断用户是否登录

要判断用户是否已登录,是非常简单的,只要有个变量记录用户登录的状态即可。在login/reset类中使用这段代码:

  1. def logged():
  2. if session.login==1:
  3. return True
  4. else:
  5. return False

第四步:简单的权限管理

我把我的用户划为四类:管理员,用户,读者(已登录),访客(未登录)。根据example_users表中定义的不同权限,选择不同的模板路径。

  1. def create_render(privilege):
  2. if logged():
  3. if privilege==0:
  4. render = render_mako(
  5. directories=['templates/reader'],
  6. input_encoding='utf-8',
  7. output_encoding='utf-8',
  8. )
  9. elif privilege==1:
  10. render = render_mako(
  11. directories=['templates/user'],
  12. input_encoding='utf-8',
  13. output_encoding='utf-8',
  14. )
  15. elif privilege==2:
  16. render = render_mako(
  17. directories=['templates/admin'],
  18. input_encoding='utf-8',
  19. output_encoding='utf-8',
  20. )
  21. else:
  22. render = render_mako(
  23. directories=['templates/communs'],
  24. input_encoding='utf-8',
  25. output_encoding='utf-8',
  26. )
  27. return render

第五:登录(Login)和注销(Reset)的python类

现在,让我们用个轻松的方法来解决:

  • 如果你已登录,就直接重定向到login_double.html模板文件
  • 否则,还是到login.html。

class login: def GET(self): if logged(): render = create_render(session.privilege) return “%s” % render.login_double() else: render = create_render(session.privilege) return “%s” % (render.login())

  • 好了。现在写POST()方法。从.html文件中,我们得到表单提交的变量值(见login.html),并根据变量值得到example_users表中对应的user数据
  • 如果登录通过了,就重定向到login_ok.html。
  • 如果没通过,就重定向到login_error.html。
  1. def POST(self):
  2. user, passwd = web.input().user, web.input().passwd
  3. ident = db.query("select * from example_users where user = '%s'" % (user)).getresult()
  4. try:
  5. if passwd==ident[0][2]:
  6. session.login=1
  7. session.privilege=ident[0][4]
  8. render = create_render(session.privilege)
  9. return "%s" % (
  10. render.login_ok()
  11. )
  12. else:
  13. session.login=0
  14. session.privilege=0
  15. render = create_render(session.privilege)
  16. return render.login_error()
  17. except:
  18. session.login=0
  19. session.privilege=0
  20. render = create_render(session.privilege)
  21. return render.login_error()

对于reset方法,只要清除用户session,再重定向到logout.html模板页即可。

  1. class reset:
  2. def GET(self):
  3. session.login=0
  4. session.kill()
  5. render = create_render(session.privilege)
  6. return render.logout()

6th: 第六步:HTML模板帮助

嗯,我认为没有人想看这个,但我喜欢把所有的信息都提供出来。最重要的就是login.html。

  1. <FORM action=/login method=POST>
  2. <table id="login">
  3. <tr>
  4. <td>User: </td>
  5. <td><input type=text name='user'></td>
  6. </tr>
  7. <tr>
  8. <td>Password: </td>
  9. <td><input type="password" name=passwd></td>
  10. </tr>
  11. <tr>
  12. <td></td>
  13. <td><input type=submit value=LOGIN></td>
  14. </tr>
  15. </table>
  16. </form>

第七:问题或疑问?

  • 邮件:您可以联想我,我的邮箱是guillaume(at)process-evolution(dot)fr
  • IRC:#webpy on irc.freenode.net (pseudo: Ephedrax)