免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
從頭搭建一個flask鑒權系統(tǒng)之登陸

 從今天開始,準備從頭開始搭建一個基于flask的鑒權系統(tǒng),一點一滴,積累于生活


從登陸開始


01.知識樹


本文涉及到如下知識點

1. flask-login的簡單使用

2. 本地鑒權實踐

3. GitHub鑒權登陸實踐,flask-github使用

4. 可擴展的表結構設計思路


02.表結構設計


我們首先設計一個User用戶表,里面的字段可以包括username,password,email等用戶信息,大致如下


usernamepasswordemail
user1p1user1@gmail.com
user2p2user2@gmail.com
user3p3user3@gmail.com


因為我們還會涉及到第三方登陸,那么為了后面便于擴展,再設計一張表,就命名為ThirdAuth,里面可以包括user_id,與user表關聯(lián),oauth_name,oauth_access_token等字段


user_idoauth_nameoauth_access_token
user-id1auth1token1
user-id2auth2token2
user-id3auth3token3


這樣,oauth_name字段可以用來存儲第三方來源,例如github,以此來區(qū)別不同的第三方登陸用戶。

到此,一個簡單的表結構就設計好了。


03.OAuth鑒權


簡單來說,為一個網(wǎng)站添加第三方登錄指的是提供通過其他第三方平臺賬號登入當前網(wǎng)站的功能。比如,使用QQ、微信、新浪微博賬號登錄。對于某些網(wǎng)站,甚至可以僅提供社交賬號登錄的選項,這樣網(wǎng)站本身就不需要管理用戶賬戶等相關信息。對用戶來說,使用第三方登錄可以省去注冊的步驟,更加方便和快捷。這里,我就是使用GitHub的OAuth認證來進行鑒權登陸。

這里首先需要在自己的GitHub上創(chuàng)建一個OAuth程序,非常簡單,訪問這個地址:https://github.com/settings/applications/new,按照要求填寫即可。



其中的callback需要填寫一個回調函數(shù),具體后面再說。

創(chuàng)建好這個OAuth程序后,我們就會獲得Client ID(客戶端ID)和Client Secret(客戶端密鑰),在后面調用Github的API時使用。


04. 本地鑒權


1. 創(chuàng)建表結構

根據(jù)剛才的表結構設計,對于本地鑒權,可以在models.py文件中創(chuàng)建一個WebUser類,定義對應的數(shù)據(jù)庫字段。

對于password,不建議直接在數(shù)據(jù)庫中存儲明文,所以這里使用了werkzeug庫來做hash轉換。

同時WebUser類還繼承自flask-login的UserMixin類,該類實現(xiàn)了關鍵的用于檢測用戶狀態(tài)的方法:

    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()
        if users is None:
            users = WebUser(email='admin@123.com', username='admin', user_id=time.time())
        users.password = '123456'
        db.session.add(users)
        db.session.commit()

    @property
    def password(self):
        raise AttributeError('password is not readable attribute')

    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password):
        return check_password_hash(self.password_hash, password)


2. 定義登陸表單

登陸表單比較簡單,兩個輸入框,分別為用戶名和密碼,一個check box,用來選擇是否保持登陸,外加一個提交按鈕

class LoginForm(FlaskForm):
    email = StringField('Email', validators=[DataRequired(), Length(164), Email()])
    password = PasswordField('Password', validators=[DataRequired()])
    remember_me = BooleanField('Keep me logged in')
    submit = SubmitField('Log In')


3. 定義登陸登出函數(shù)

當表單正確提交時,如果用戶名和密碼匹配,則提示登陸成功,并跳轉頁面,否則提示登陸失敗。

因為是使用flask-login擴展,所以登陸直接調用login_user()即可。

@auth.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        user = WebUser.query.filter_by(email=form.email.data).first()
        if user is not None and user.verify_password(form.password.data):
            login_user(user, form.remember_me.data)
            return redirect(request.args.get('next'or url_for('main.index'))
        flash('Invalid username or password!')
    return render_template('auth/login.html', form=form)


對于登出,同樣簡單,注意需要用login_required裝飾器保證只有已經登陸的用戶才能調用該函數(shù)。

@auth.route('/logout')
@login_required
def logout():
    flash('You have logged out!')
    return redirect(url_for('main.index'))


4. web模板

創(chuàng)建一個base.html基礎模板(繼承自flask-bootstrap模板),后面其他頁面都繼承自該模板,這樣可以保證所有的頁面風格統(tǒng)一,也可以減少代碼量。

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

{% block title %}Flasky{% endblock %} 

{% block navbar %}
<div class='navbar navbar-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'>Toggle navigation</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-collapse collapse'>
            <ul class='nav navbar-nav'>
                <li><a href='/'>Home</a></li>
            </ul>
            <ul class='nav navbar-nav navbar-right'>
                {% if current_user.is_authenticated %}
                <li><a href='{{ url_for('auth.logout') }}'>Sign Out</a></li>
                {% else %}
                <li><a href='{{ url_for('auth.login') }}'>Sign In</a></li>
                {% endif %}
            </ul>
        </div>
    </div>
</div>
{% endblock %}

{% block content %}
<div class='container'>
    {% block page_content %}{% endblock %}
</div>
{% endblock %}


5. 登陸頁面

登陸頁面繼承自base.html模板,并使用wtf快速渲染表單

{% extends 'base.html' %}
{% import  'bootstrap/wtf.html' as wtf %}
{% block title %}Login{% endblock %}
{% block page_content %}
<div class='page-header'>
    <h1>Login</h1>
</div>

<div class='col-md-4'>
    {{ wtf.quick_form(form) }}
</div>
{% endblock %}


最后的登陸頁面為



6. 初始化數(shù)據(jù)庫

使用flask-script擴展,定義runserver和shell兩個命令行命令,shell用于數(shù)據(jù)庫等調測操作,runserver用于啟動服務。

from app import create_app, db
from flask_script import Manager, Shell, Server
from app.models import WebUser


app = create_app('testing')
manager = Manager(app)


def make_shell_context():
    return dict(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(),分別創(chuàng)建表并插入原始用戶。


7. 登陸測試

在輸入框分別鍵入admin@163.com和123456,并點擊登陸,發(fā)現(xiàn)可以正常登陸,效果如下



其中index頁面代碼為

{% extends 'base.html' %}
{% import  'bootstrap/wtf.html' as wtf %}
{% block title %}Login{% endblock %}
{% block page_content %}
<div class='container'>
    {% for message in get_flashed_messages() %}
    <div class='alert alert-warning'>
        <button type='buttonclass='closedata-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 }}' />
    </div>
{% else %}
    Your are not login yet
{% endif %}
</div>
{% endblock %}


05. GitHub鑒權


1. 創(chuàng)建表結構

類似的,定義需要的字段即可

class ThirdOAuth(db.Model):
    __tablename__ = 'thirdoauth'
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.String(64), unique=True, index=True)
    oauth_name = db.Column(db.String(128))
    oauth_id = db.Column(db.String(128), unique=True, index=True)
    oauth_access_token = db.Column(db.String(128), unique=True, index=True)
    oauth_expires = db.Column(db.String(64), unique=True, index=True)


2. 發(fā)送授權請求

這一步,flask-github已經為我們封裝好了,直接調用即可

@auth.route('/githublogin', methods=['GET', 'POST'])
def githublogin():
    return github.authorize(scope='repo')


這里需要說明,該調用需要用到我們前面獲得的客戶端ID和密鑰,我這里把相關信息寫到了一個配置文件中,并在初始化flask app時加載

配置文件

class Config:
    SECRET_KEY = 'hardtoguess'
    GITHUB_CLIENT_ID = 'cf1AA35ef11d20bcdXXX'
    GITHUB_CLIENT_SECRET = 'ba7c8c8SSe9cd574eb3da1b5e704d11d35aXXXb8'


初始化app

def create_app(config_name):
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    config[config_name].init_app(app)
    db.init_app(app)
    cors.init_app(app, supports_credentials=True)
    login_manager.init_app(app)
    bootstrap.init_app(app)
    github.init_app(app)

    from .main import main as main_blueprint
    app.register_blueprint(main_blueprint)
    from .api_1_0 import api_1_0 as api_blueprint
    app.register_blueprint(api_blueprint)
    from .auth import auth as auth_blueprint
    app.register_blueprint(auth_blueprint, url_prefix='/auth')

    return app


3. 獲取access令牌

當用戶同意授權或拒絕授權后,GitHub會將用戶重定向到我們設置的callback URL,我們需要創(chuàng)建一個視圖函數(shù)來處理回調請求。如果用戶同意授權,GitHub會在重定向的請求中加入code參數(shù),一個臨時生成的值,用于程序再次發(fā)起請求交換access token。程序這時需要向請求訪問令牌URL(即https://github.com/login/oauth/access_token)發(fā)起一個POST請求,附帶客戶端ID、客戶端密鑰、code。請求成功后的的響應會包含訪問令牌(Access Token)。


很幸運,上面的一系列工作flask-github會在背后替我們完成。我們只需要創(chuàng)建一個視圖函數(shù),定義正確的URL規(guī)則(這里的URL規(guī)則需要和GitHub上填寫的Callback URL匹配),并為其附加一個github.authorized_handler裝飾器。另外,這個函數(shù)要接受一個access_token參數(shù),GitHub-Flask會在授權請求結束后通過這個參數(shù)傳入訪問令牌。

同時判斷,該用戶是否存在于數(shù)據(jù)庫中,并更新相關字段。

@auth.route('/callback/github')
@github.authorized_handler
def authorized(access_token):
    if access_token is None:
        flash('Login Failed!')
        return redirect(url_for('main.index'))
    response = github.get('user', access_token=access_token)
    username = response['login']
    u_id = response['id']
    email = response['email']
    avatar = response['avatar_url']
    user = WebUser.query.filter_by(username=username).first()
    if user is None:
        user = WebUser(username=username, user_id=time.time())
        db.session.add(user)
        db.session.commit()
        thirduser = ThirdOAuth(user_id=WebUser.query.filter_by(username=username).first().user_id,
                               oauth_name='github', oauth_access_token=access_token,
                               oauth_id=u_id)
        db.session.add(thirduser)
        db.session.commit()
        login_user(user)
        user.email = email
        db.session.add(user)
        db.session.commit()
        session['userid'] = user.user_id
        return render_template('index.html', avatar=avatar)
    else:
        thirduser = ThirdOAuth.query.filter_by(user_id=user.user_id).first()
        thirduser.oauth_access_token = access_token
        db.session.add(thirduser)
        db.session.commit()
        user.email = email
        db.session.add(user)
        db.session.commit()
        login_user(user)
        session['userid'] = user.user_id
        return render_template('index.html', avatar=avatar)


更多的GitHub開發(fā)文檔資料可以查看:

https://developer.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/

更多flask-github資料可以查看:

https://github-flask.readthedocs.io/en/latest/


4. 更新登陸頁面

更新登陸頁面,增加一個以GitHub登陸的按鈕

<div class='col-md-12'>
    <a class='btn btn-primary' href='{{ url_for('auth.githublogin') }}'>Login with GitHub</a>
</div>


現(xiàn)在的登陸頁面為


更新index路由函數(shù),增加以GitHub登陸時的頭像

@main.route('/', methods=['GET', 'POST'])
def index():
    # print(session)
    if current_user.is_authenticated:
        if 'userid' in session:
            user = ThirdOAuth.query.filter_by(user_id=session['userid']).first()
            if user:
                response = github.get('user', access_token=user.oauth_access_token)
                avatar = response['avatar_url']
                username = response['login']
                return render_template('index.html', username=username, avatar=avatar)
    return render_template('index.html')


又因為在callback函數(shù)中增加了session.userid字段,所以在logout時,把該字段手動刪除

@auth.route('/logout')
@login_required
def logout():
    logout_user()
    if 'userid' in session:
        session.pop('userid')
    flash('You have logged out!')
    return redirect(url_for('main.index'))


5. 測試GitHub登陸

登陸成功后,如下



至此,登陸功能完成


完整代碼:

https://github.com/zhouwei713/flask-webauth



本站僅提供存儲服務,所有內容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
使用Flask設計帶認證token的RESTful API接口[翻譯]
Python Flask Restful token驗證
PHP調用新浪微博開放平臺api發(fā)送微博實例
Django中使用第三方登錄
第 82 天:Python Web 開發(fā)之 JWT 簡介
為PHPBB加一個oauth認證方式統(tǒng)一登陸SSO
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服