使用 Flask 和 rauth 進行 Github Oauth 登陸
來自: http://python.jobbole.com/84283/
最近我研究了一下Flask的OAuth庫。情況并不樂觀,大部分的包都已過時并且不再被支持了。大家熟知的Flask-Oauth基本上已經被廢棄了,我也不推薦依賴這個庫。有趣的是OAuth本身其實是很簡單的,認證之后你會得到一個訪問token,你只需將其作為GET參數或者作為request的特殊的header即可。也許其他的OAuth提供者需要更復雜的邏輯,但是Github僅此就足夠。
我在StackOverflow上請教了如何解決Flask-OAuth的問題 ,從rauth的作者那里得到回答,他建議試一下他寫的庫。本文就是對他及開源社區的回報。我寫了這個真實的例子,告訴你如何使用Flask、rauth、Github和會話來對你的站點的用戶進行認證。
首先你需要設置好本地的環境。你需要安裝好python、pip和virtualenv。接下來對環境進行設置:
$ virtualenv venv $ source venv/bin/activate (venv)$ pip install rauth Flask Flask-SQLAlchemy
$ virtualenvvenv $ sourcevenv/bin/activate (venv)$ pipinstallrauthFlaskFlask-SQLAlchemy
如果要運行我的例子,你還需要安裝Sqlite的python綁定,SQLAlchemy會需要它:
(venv)$ pip install pysqlite
(venv)$ pipinstallpysqlite
pip會安裝所有需要的依賴,所以你的環境已經就緒了。
現在你需要到Github設置頁面里找到 Applications sections ,為你設置好一個新的應用。下圖顯示了在我的配置區域。
下面是代碼,主模塊如下:
# github.py from flask import (Flask, flash, request, redirect, render_template, url_for, session) from flask.ext.sqlalchemy import SQLAlchemy from rauth.service import OAuth2Service # Flask config SQLALCHEMY_DATABASE_URI = 'sqlite:///github.db' SECRET_KEY = '\xfb\x12\xdf\xa1@i\xd6>V\xc0\xbb\x8fp\x16#Z\x0b\x81\xeb\x16' DEBUG = True # Flask setup app = Flask(__name__) app.config.from_object(__name__) db = SQLAlchemy(app) # Use your own values in your real application github = OAuth2Service( name='github', base_url='https://api.github.com/', access_token_url='https://github.com/login/oauth/access_token', authorize_url='https://github.com/login/oauth/authorize', client_id= '477151a6a9a9a25853de', client_secret= '23b97cc6de3bea712fddbef70a5f5780517449e4', ) # models class User(db.Model): id = db.Column(db.Integer, primary_key=True) login = db.Column(db.String(80), unique=True) name = db.Column(db.String(120)) def __init__(self, login, name): self.login = login self.name = name def __repr__(self): return '<User %r>' % self.login @staticmethod def get_or_create(login, name): user = User.query.filter_by(login=login).first() if user is None: user = User(login, name) db.session.add(user) db.session.commit() return user # views @app.route('/') def index(): return render_template('login.html') @app.route('/about') def about(): if session.has_key('token'): auth = github.get_session(token = session['token']) resp = auth.get('/user') if resp.status_code == 200: user = resp.json() return render_template('about.html', user = user) else: return redirect(url_for('login')) @app.route('/login') def login(): redirect_uri = url_for('authorized', next=request.args.get('next') or request.referrer or None, _external=True) print(redirect_uri) # More scopes http://developer.github.com/v3/oauth/#scopes params = {'redirect_uri': redirect_uri, 'scope': 'user:email'} print(github.get_authorize_url(**params)) return redirect(github.get_authorize_url(**params)) # same path as on application settings page @app.route('/github/callback') def authorized(): # check to make sure the user authorized the request if not 'code' in request.args: flash('You did not authorize the request') return redirect(url_for('index')) # make a request for the access token credentials using code redirect_uri = url_for('authorized', _external=True) data = dict(code=request.args['code'], redirect_uri=redirect_uri, scope='user:email,public_repo') auth = github.get_auth_session(data=data) # the "me" response me = auth.get('user').json() user = User.get_or_create(me['login'], me['name']) session['token'] = auth.access_token session['user_id'] = user.id flash('Logged in as ' + me['name']) return redirect(url_for('index')) if __name__ == '__main__': db.create_all() app.run()
# github.py fromflaskimport (Flask, flash, request, redirect, render_template, url_for, session) fromflask.ext.sqlalchemyimportSQLAlchemy fromrauth.serviceimportOAuth2Service # Flask config SQLALCHEMY_DATABASE_URI = 'sqlite:///github.db' SECRET_KEY = '\xfb\x12\xdf\xa1@i\xd6>V\xc0\xbb\x8fp\x16#Z\x0b\x81\xeb\x16' DEBUG = True # Flask setup app = Flask(__name__) app.config.from_object(__name__) db = SQLAlchemy(app) # Use your own values in your real application github = OAuth2Service( name='github', base_url='https://api.github.com/', access_token_url='https://github.com/login/oauth/access_token', authorize_url='https://github.com/login/oauth/authorize', client_id= '477151a6a9a9a25853de', client_secret= '23b97cc6de3bea712fddbef70a5f5780517449e4', ) # models class User(db.Model): id = db.Column(db.Integer, primary_key=True) login = db.Column(db.String(80), unique=True) name = db.Column(db.String(120)) def__init__(self, login, name): self.login = login self.name = name def__repr__(self): return '<User %r>' % self.login @staticmethod defget_or_create(login, name): user = User.query.filter_by(login=login).first() if useris None: user = User(login, name) db.session.add(user) db.session.commit() return user # views @app.route('/') defindex(): return render_template('login.html') @app.route('/about') defabout(): if session.has_key('token'): auth = github.get_session(token = session['token']) resp = auth.get('/user') if resp.status_code == 200: user = resp.json() return render_template('about.html', user = user) else: return redirect(url_for('login')) @app.route('/login') deflogin(): redirect_uri = url_for('authorized', next=request.args.get('next') or request.referreror None, _external=True) print(redirect_uri) # More scopes http://developer.github.com/v3/oauth/#scopes params = {'redirect_uri': redirect_uri, 'scope': 'user:email'} print(github.get_authorize_url(**params)) return redirect(github.get_authorize_url(**params)) # same path as on application settings page @app.route('/github/callback') defauthorized(): # check to make sure the user authorized the request if not 'code' in request.args: flash('You did not authorize the request') return redirect(url_for('index')) # make a request for the access token credentials using code redirect_uri = url_for('authorized', _external=True) data = dict(code=request.args['code'], redirect_uri=redirect_uri, scope='user:email,public_repo') auth = github.get_auth_session(data=data) # the "me" response me = auth.get('user').json() user = User.get_or_create(me['login'], me['name']) session['token'] = auth.access_token session['user_id'] = user.id flash('Logged in as ' + me['name']) return redirect(url_for('index')) if __name__ == '__main__': db.create_all() app.run()
模板:
<!-- templates/about.html --> <!doctype html> <title>Login</title> <h1>About you</h1> Welcome , and your email is <br /> <a href ="">Main page</a>
<!-- templates/about.html --> <!doctypehtml> <title>Login</title> <h1>Aboutyou</h1> Welcome , and youremailis <br /> <a href ="">Mainpage</a>
<!-- templates/login.html --> <!doctype html> <title>Login</title> <h1>Login</h1> <a href ="">Login with OAuth2</a> <h1>About</h1> <a href="">About</a> If you are not logged in then you will be redirected to login page.
<!-- templates/login.html --> <!doctypehtml> <title>Login</title> <h1>Login</h1> <a href ="">LoginwithOAuth2</a> <h1>About</h1> <a href="">About</a> If youarenot loggedin then youwillberedirectedto loginpage.
啟動后將創建數據庫:
(venv)$ python github.py
(venv)$ pythongithub.py
在瀏覽器打開網站后,將在 session 保存 login.access_token,這是不安全的,但作為例子已經足夠了。實際的網站中你可以這樣使用:
# Probably your User model placed in different blueprint from authmodule.models import User @app.before_request def before_request(): g.user = None if 'user_id' in session: if session['user_id']: user = User.query.get(session['user_id']) if user: g.user = user else: del session['user_id']
# Probably your User model placed in different blueprint fromauthmodule.modelsimportUser @app.before_request defbefore_request(): g.user = None if 'user_id' in session: if session['user_id']: user = User.query.get(session['user_id']) if user: g.user = user else: delsession['user_id']
本文由用戶 lihua184 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!