├── .flaskenv
├── static
├── favicon.ico
└── styles.css
├── Pipfile
├── templates
├── index.html
└── base.html
├── README.md
├── LICENSE
├── .gitignore
└── app.py
/.flaskenv:
--------------------------------------------------------------------------------
1 | FLASK_ENV=development
--------------------------------------------------------------------------------
/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/helloflask/github-login/master/static/favicon.ico
--------------------------------------------------------------------------------
/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | url = "https://pypi.org/simple"
3 | verify_ssl = true
4 | name = "pypi"
5 |
6 | [dev-packages]
7 |
8 | [packages]
9 | flask = "*"
10 | flask-sqlalchemy = "*"
11 | github-flask = "*"
12 |
--------------------------------------------------------------------------------
/templates/index.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block content %}
4 |
Login with GitHub
5 | with GitHub-Flask
6 | {% if is_login %}
7 | Hello, {{ username }} !
8 | Look, we get this avatar from your GitHub account :
9 |
10 | You can click here to see more information we get.
11 | Try to star this repo on GitHub with the button below:
12 | Star HelloFlask on GitHub
13 | Logout
14 | {% else %}
15 | Login with GitHub
16 | {% endif %}
17 | {% endblock %}
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GitHub-Login
2 | Example application for login with GitHub by GitHub-Flask
3 |
4 | ## Online Demo
5 | https://helloflask.pythonanywhere.com
6 |
7 | ## Installation
8 |
9 | ```
10 | $ git clone https://github.com/helloflask/github-login
11 | $ cd github-login
12 | ```
13 |
14 | ## Register Your OAuth Application on GitHub
15 |
16 | Go to https://github.com/settings/applications/new
17 |
18 | Fill the form, then you will get your Client ID and Client Secret, write them into
19 | app.py:
20 |
21 | ```python
22 | app.config['GITHUB_CLIENT_ID'] = 'your_client_id'
23 | app.config['GITHUB_CLIENT_SECRET'] = 'your_clent_secret'
24 |
25 | ```
26 | *Warning: You normally need to save this values as enviroment variable in production.*
27 |
28 | ## Run
29 |
30 | Just excute:
31 | ```
32 | $ flask run
33 | ```
34 | Then go to http://localhost:5000
35 |
36 |
37 | # For Readers of Hello, Flask!
38 |
39 | 这个示例程序的介绍文章为[《使用GitHub-Flask实现GitHub第三方登录》](https://zhuanlan.zhihu.com/p/39026635)。
40 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Hello, Flask!
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/templates/base.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {% block head %}
5 |
6 | {% block title %}GitHub Login - HelloFlask{% endblock %}
7 |
8 | {% block styles %}
9 |
10 | {% endblock %}
11 | {% endblock %}
12 |
13 |
14 |
15 |
18 |
19 |
20 |
21 | {% for message in get_flashed_messages() %}
22 |
23 | {{ message }}
24 |
25 | {% endfor %}
26 | {% block content %}{% endblock %}
27 |
28 |
36 | {% block scripts %}{% endblock %}
37 |
38 |
39 |
--------------------------------------------------------------------------------
/static/styles.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: auto;
3 | width: 750px;
4 | }
5 |
6 | nav ul {
7 | list-style-type: none;
8 | margin: 0;
9 | padding: 0;
10 | overflow: hidden;
11 | background-color: #333;
12 | }
13 |
14 | nav li {
15 | float: left;
16 | }
17 |
18 | nav li a {
19 | display: block;
20 | color: white;
21 | text-align: center;
22 | padding: 14px 16px;
23 | text-decoration: none;
24 | }
25 |
26 | nav li a:hover {
27 | background-color: #111;
28 | }
29 |
30 | main {
31 | padding: 10px 20px;
32 | }
33 |
34 | footer {
35 | font-size: 13px;
36 | color: #888;
37 | border-top: 1px solid #eee;
38 | margin-top: 25px;
39 | text-align: center;
40 | padding: 20px;
41 |
42 | }
43 |
44 | .alert {
45 | position: relative;
46 | padding: 0.75rem 1.25rem;
47 | margin-bottom: 1rem;
48 | border: 1px solid transparent;
49 | border-radius: 0.25rem;
50 | color: #004085;
51 | background-color: #cce5ff;
52 | border-color: #b8daff;
53 | }
54 |
55 | .note p {
56 | padding: 10px;
57 | border-left: solid 2px #bbb;
58 | }
59 |
60 | .note form {
61 | display: inline;
62 | }
63 |
64 |
65 | .btn {
66 | font-family: Arial;
67 | font-size: 14px;
68 | padding: 5px 10px;
69 | text-decoration: none;
70 | border:none;
71 | cursor: pointer;
72 | background-color: white;
73 | color: black;
74 | border: 2px solid #555555;
75 | }
76 |
77 | .btn:hover {
78 | text-decoration: none;
79 | background-color: black;
80 | color: white;
81 | border: 2px solid black;
82 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 | .pytest_cache/
49 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | local_settings.py
57 | db.sqlite3
58 |
59 | # Flask stuff:
60 | instance/
61 | .webassets-cache
62 |
63 | # Scrapy stuff:
64 | .scrapy
65 |
66 | # Sphinx documentation
67 | docs/_build/
68 |
69 | # PyBuilder
70 | target/
71 |
72 | # Jupyter Notebook
73 | .ipynb_checkpoints
74 |
75 | # pyenv
76 | .python-version
77 |
78 | # celery beat schedule file
79 | celerybeat-schedule
80 |
81 | # SageMath parsed files
82 | *.sage.py
83 |
84 | # Environments
85 | .env
86 | .venv
87 | env/
88 | venv/
89 | ENV/
90 | env.bak/
91 | venv.bak/
92 |
93 | # Spyder project settings
94 | .spyderproject
95 | .spyproject
96 |
97 | # Rope project settings
98 | .ropeproject
99 |
100 | # mkdocs documentation
101 | /site
102 |
103 | # mypy
104 | .mypy_cache/
105 |
106 | # database
107 | *.db
108 |
109 |
--------------------------------------------------------------------------------
/app.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | :author: Grey Li (李辉)
4 | :url: http://greyli.com
5 | :copyright: © 2018 Grey Li
6 | :license: MIT, see LICENSE for more details.
7 | """
8 | import os
9 | import sys
10 |
11 | import click
12 | from flask import Flask, request, g, session, redirect, url_for, render_template, jsonify, flash
13 | from flask_github import GitHub
14 | from flask_sqlalchemy import SQLAlchemy
15 |
16 | # sqlite URI compatible
17 | WIN = sys.platform.startswith('win')
18 | if WIN:
19 | prefix = 'sqlite:///'
20 | else:
21 | prefix = 'sqlite:////'
22 |
23 | app = Flask(__name__)
24 | app.jinja_env.trim_blocks = True
25 | app.jinja_env.lstrip_blocks = True
26 |
27 | app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'secret string')
28 | # Flask-SQLAlchemy
29 | app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL', prefix + os.path.join(app.root_path, 'data.db'))
30 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
31 | # GitHub-Flask
32 | # Register your OAuth application on https://github.com/settings/applications/new
33 | # You normally need to save this values as enviroment variable
34 | app.config['GITHUB_CLIENT_ID'] = 'your_client_id'
35 | app.config['GITHUB_CLIENT_SECRET'] = 'your_clent_secret'
36 |
37 | db = SQLAlchemy(app)
38 | github = GitHub(app)
39 |
40 |
41 | @app.cli.command()
42 | @click.option('--drop', is_flag=True, help='Create after drop.')
43 | def initdb(drop):
44 | """Initialize the database."""
45 | if drop:
46 | db.drop_all()
47 | db.create_all()
48 | click.echo('Initialized database.')
49 |
50 |
51 | class User(db.Model):
52 | id = db.Column(db.Integer, primary_key=True)
53 | username = db.Column(db.String(100))
54 | access_token = db.Column(db.String(200))
55 |
56 |
57 | @app.before_request
58 | def before_request():
59 | g.user = None
60 | if 'user_id' in session:
61 | g.user = User.query.get(session['user_id'])
62 |
63 |
64 | @app.route('/')
65 | def index():
66 | if g.user:
67 | is_login = True
68 | response = github.get('user')
69 | avatar = response['avatar_url']
70 | username = response['name']
71 | url = response['html_url']
72 | return render_template('index.html', is_login=is_login, avatar=avatar, username=username, url=url)
73 | is_login = False
74 | return render_template('index.html', is_login=is_login)
75 |
76 |
77 | @app.route('/star/helloflask')
78 | def star():
79 | github.put('user/starred/greyli/helloflask', headers={'Content-Length': '0'})
80 | flash('Star success.')
81 | return redirect(url_for('index'))
82 |
83 |
84 | @github.access_token_getter
85 | def token_getter():
86 | user = g.user
87 | if user is not None:
88 | return user.access_token
89 |
90 |
91 | @app.route('/callback/github')
92 | @github.authorized_handler
93 | def authorized(access_token):
94 | if access_token is None:
95 | flash('Login failed.')
96 | return redirect(url_for('index'))
97 |
98 | response = github.get('user', access_token=access_token)
99 | username = response['login'] # get username
100 | user = User.query.filter_by(username=username).first()
101 | if user is None:
102 | user = User(username=username, access_token=access_token)
103 | db.session.add(user)
104 | user.access_token = access_token # update access token
105 | db.session.commit()
106 | flash('Login success.')
107 | # log the user in
108 | # if you use flask-login, just call login_user() here.
109 | session['user_id'] = user.id
110 | return redirect(url_for('index'))
111 |
112 |
113 | @app.route('/login')
114 | def login():
115 | if session.get('user_id', None) is None:
116 | return github.authorize(scope='repo')
117 | flash('Already logged in.')
118 | return redirect(url_for('index'))
119 |
120 |
121 | @app.route('/logout')
122 | def logout():
123 | session.pop('user_id', None)
124 | flash('Goodbye.')
125 | return redirect(url_for('index'))
126 |
127 |
128 | @app.route('/user')
129 | def get_user():
130 | return jsonify(github.get('user'))
131 |
--------------------------------------------------------------------------------