python123平台登陆页_从头搭建一个flask鉴权系统之登陆

从今天开始,准备从头开始搭建一个基于flask的鉴权系统,一点一滴,积累于生活”

从登陆开始

01.

知识树

本文涉及到如下知识点

1. flask-login的简单使用

2. 本地鉴权实践

3. GitHub鉴权登陆实践,flask-github使用

4. 可扩展的表结构设计思路

02.

表结构设计

我们首先设计一个User用户表,里面的字段可以包括username,password,email等用户信息,大致如下[email protected]

[email protected]

[email protected]

因为我们还会涉及到第三方登陆,那么为了后面便于扩展,再设计一张表,就命名为ThirdAuth,里面可以包括user_id,与user表关联,oauth_name,oauth_access_token等字段user_idoauth_nameoauth_access_tokenuser-id1auth1token1

user-id2auth2token2

user-id3auth3token3

这样,oauth_name字段可以用来存储第三方来源,例如github,以此来区别不同的第三方登陆用户。

到此,一个简单的表结构就设计好了。

03.OAuth鉴权

简单来说,为一个网站添加第三方登录指的是提供通过其他第三方平台账号登入当前网站的功能。比如,使用QQ、微信、新浪微博账号登录。对于某些网站,甚至可以仅提供社交账号登录的选项,这样网站本身就不需要管理用户账户等相关信息。对用户来说,使用第三方登录可以省去注册的步骤,更加方便和快捷。这里,我就是使用GitHub的OAuth认证来进行鉴权登陆。

这里首先需要在自己的GitHub上创建一个OAuth程序,非常简单,访问这个地址:https://github.com/settings/applications/new,按照要求填写即可。

其中的callback需要填写一个回调函数,具体后面再说。

创建好这个OAuth程序后,我们就会获得Client ID(客户端ID)和Client Secret(客户端密钥),在后面调用Github的API时使用。

04. 本地鉴权

1. 创建表结构

根据刚才的表结构设计,对于本地鉴权,可以在models.py文件中创建一个WebUser类,定义对应的数据库字段。

对于password,不建议直接在数据库中存储明文,所以这里使用了werkzeug库来做hash转换。

同时WebUser类还继承自flask-login的UserMixin类,该类实现了关键的用于检测用户状态的方法:

is_authenticated,如果用户已经登陆返回True,否则返回False

is_active,如果用户允许登陆,返回True,否则返回Flase

is_anonymous,对普通用户必须返回False

get_id,必须返回用户的唯一标识

后面主要使用到了

is_authenticated方法。

而init_user是用来初始化第一个用户的,password等几个方法分别是用来检测密码是否正确的。

class

WebUser

(UserMixin,db.Model):

__tablename__=

"webuser"

id=db.Column(db.Integer,primary_key=

True)

user_id=db.Column(db.String(

64),unique=

True,index=

True)

email=db.Column(db.String(

64),unique=

True,index=

True)

username=db.Column(db.String(

64),unique=

True,index=

True)

password_hash=db.Column(db.String(

128))

@staticmethod

def

init_user

():

users=WebUser.query.filter_by(username=

"admin").first()

ifusers

is

None:

users=WebUser(email=

"[email protected]",username=

"admin",user_id=time.time())

users.password=

"123456"

db.session.add(users)

db.session.commit()

@property

def

password

(self):

raiseAttributeError(

"passwordisnotreadableattribute")

@password.setter

def

password

(self,password):

self.password_hash=generate_password_hash(password)

def

verify_password

(self,password):

returncheck_password_hash(self.password_hash,password)

2. 定义登陆表单

登陆表单比较简单,两个输入框,分别为用户名和密码,一个check box,用来选择是否保持登陆,外加一个提交按钮class

LoginForm

(FlaskForm):

email=StringField(

"Email",validators=[DataRequired(),Length(

1,

64),Email()])

password=PasswordField(

"Password",validators=[DataRequired()])

remember_me=BooleanField(

"Keepmeloggedin")

submit=SubmitField(

"LogIn")

3. 定义登陆登出函数

当表单正确提交时,如果用户名和密码匹配,则提示登陆成功,并跳转页面,否则提示登陆失败。

因为是使用flask-login扩展,所以登陆直接调用login_user()即可。

@auth.route("/login",methods=["GET","POST"])

def

login

():

form=LoginForm()

ifform.validate_on_submit():

user=WebUser.query.filter_by(email=form.email.data).first()

ifuser

is

not

None

anduser.verify_password(form.password.data):

login_user(user,form.remember_me.data)

returnredirect(request.args.get(

"next")

orurl_for(

"main.index"))

flash(

"Invalidusernameorpassword!")

returnrender_template(

"auth/login.html",form=form)

对于登出,同样简单,注意需要用login_required装饰器保证只有已经登陆的用户才能调用该函数。@auth.route("/logout")

@login_required

def

logout

():

flash(

"Youhaveloggedout!")

returnredirect(url_for(

"main.index"))

4. web模板

创建一个base.html基础模板(继承自flask-bootstrap模板),后面其他页面都继承自该模板,这样可以保证所有的页面风格统一,也可以减少代码量。

{%extends"bootstrap/base.html"%}

{%blocktitle%}Flasky{%endblock%}

{%blocknavbar%}

<

div

class=

"navbarnavbar-inverse"

role=

"navigation">

<

div

class=

"container">

<

div

class=

"navbar-header">

<

button

type=

"button"

class=

"navbar-toggle"

data-toggle=

"collapse"

data-target=

".navbar-collapse">

<

span

class=

"sr-only">Togglenavigation

span>

<

span

class=

"icon-bar">

span>

<

span

class=

"icon-bar">

span>

<

span

class=

"icon-bar">

span>

button>

<

a

class=

"navbar-brand"

href=

"/">WebAuth

a>

div>

<

div

class=

"navbar-collapsecollapse">

<

ul

class=

"navnavbar-nav">

<

li><

a

href=

"/">Home

a>

li>

ul>

<

ul

class=

"navnavbar-navnavbar-right">

{%ifcurrent_user.is_authenticated%}

<

li><

a

href=

"{{url_for("auth.logout")}}">SignOut

a>

li>

{%else%}

<

li><

a

href=

"{{url_for("auth.login")}}">SignIn

a>

li>

{%endif%}

ul>

div>

div>

div>

{%endblock%}

{%blockcontent%}

<

div

class=

"container">

{%blockpage_content%}{%endblock%}

div>

{%endblock%}

5. 登陆页面

登陆页面继承自base.html模板,并使用wtf快速渲染表单{%extends"base.html"%}

{%import"bootstrap/wtf.html"aswtf%}

{%blocktitle%}Login{%endblock%}

{%blockpage_content%}

<

div

class=

"page-header">

<

h1>Login

h1>

div>

<

div

class=

"col-md-4">

{{wtf.quick_form(form)}}

div>

{%endblock%}

最后的登陆页面为

6. 初始化数据库

使用flask-script扩展,定义runserver和shell两个命令行命令,shell用于数据库等调测操作,runserver用于启动服务。

fromapp

importcreate_app,db

fromflask_script

importManager,Shell,Server

fromapp.models

importWebUser

app=create_app(

"testing")

manager=Manager(app)

def

make_shell_context

():

returndict(app=app,db=db,WebUser=WebUser)

manager.add_command(

"runserver",Server(use_debugger=

True,host=

"0.0.0.0",port=

"9982"))

manager.add_command(

"shell",Shell(make_context=make_shell_context))

if__name__==

"__main__":

manager.run(default_command=

"runserver")

在命令行输入python manage.py shell,进入调测shell,然后输入db.create_all()和WebUser.init_user(),分别创建表并插入原始用户。

7. 登陆测试

在输入框分别键入[email protected]和123456,并点击登陆,发现可以正常登陆,效果如下

其中index页面代码为{%extends

"base.html"%}

{%

import

"bootstrap/wtf.html"

aswtf%}

{%blocktitle%}Login{%endblock%}

{%blockpage_content%}

class="

container">

{%

for

message

in

get_flashed_messages

()%}

<

div

class="

alert

alert-

warning">

<

button

type="

button"

class="

close"

data-

dismiss="

alert">&

times;

button>

{{

message}}

div>

{%

endfor%}

div>

<

div

class="

page-

header">

<

h1>

Home

h1>

div>

<

div

class="

col-

md-4">

这是首页

div>

<

div

class="

col-

md-12">

{%

if

current_user.

is_authenticated%}

{{

current_user.

username}}

{{

name}}

<

div>

<

img

style="-

webkit-

user-

select:none;

"src="{{avatar}}

"/>

{%else%}

Yourarenotloginyet

{%endif%}

你可能感兴趣的:(python123平台登陆页)