流程:
(1) 用户跳转到github 去获取权限
(2) github 授权成功会跳转回我们的网站 带回来一个code
(3) 通过第(2)中github跳转回来的code去访问 githubApi 拿到token
1.用户去github 授权,目的是授权成功后拿到code
2. 拿到 code,去交换 token
3.拿着token去访问github 获取github的用户信息
- 流程图
5.输入你的被认证的app 的名字
6. 输入被认证app 主页的名字
7. 展现给用户的描述
8.认证完后跳转到 哪个页面(回调)
9. 注册
10.授权
11.输入github 用户名秘密或者点击授权(已经登录github的)后,返回一个code 码
12.拿着 code ,client_id ,client_secret,redirect_uri ,state 去换 token
13. 拿着token 去换 用户id 和 其他信息
---------------------------------------------- 总结: -------------------------------------------------------
1.用户点击登录按钮,浏览器去访问github 服务器请求code 码,
https://github.com/login/oauth/authorize?client_id=d41ff3a3c0873a0a4b6c&redirect_uri=http://localhost:8080/callback&scope=user & state=1
出现一个github 登录界面,让用户登录授权
2.用户登录授权后,Github 服务器返回 给浏览器一个 code 码
如下:
http://localhost:8080/callback?code=ee2fa64ef1e81757a6bd
自己的服务器拦截 到code 码,
3.post 请求:
https://github.com/login/oauth/access_token
参数: client_id , client_secret , code , redirect_uri , state,
返回token令牌,
4.拿着令牌去访问 用户的信息
Request request = new Request.Builder()
.addHeader(“Authorization”,"token "+accessToken)
.url(“https://api.github.com/user?access_token=” + accessToken)
.build();
5.拿到用户的信息,进行处理
相关代码
目录结构
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1> Hello OAuth2</h1>
<hr>
<p>其他登录方式</p>
<a href="{{ context.github_auth_url }}">github登录</a> <br>
<a href="{{ context.gitee_auth_url }}">gitee登录</a>
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Home</title>
</head>
<body>
<div>
<h1>欢迎登录</h1>
{% if user_info.user_name %}
<p>用户名: {{ user_info.user_name }}</p>
{% else %}
<p>{{ user_info.msg }}</p>
{% endif %}
{% if user_info.avatar_url %}
<p>头像: <img src="{{ user_info.avatar_url }}" alt="头像信息"></p>
{% endif %}
<p>token: {{ jwt }}</p>
<a href="http://127.0.0.1:5000/source?token={{ jwt }}">获取资源列表</a>
</div>
</body>
</html>
app.py
# -*- coding:utf-8 -*-
'''
PROJECT_NAME : auth_demo
file : app5_oauth
author : 1032162439@qq.com
date : 2022-09-09 11:37
IDE : PyCharm
'''
import json
import jwt
import requests
from jwt import exceptions
from flask import Flask, render_template, request, redirect
# 实例化app对象
app = Flask(__name__)
# 设置secret key
app.secret_key = 'secret key string!'
# github 的 client id、 client secret、 redirect uri
github_client_id = 'bc19fcdf968ffbb1fa05'
github_client_secret = 'you client secret'
github_redirect_uri = 'http://127.0.0.1:5000/oauth2/github/callback'
# github 用户信息 api
github_user_info_url = 'https://api.github.com/user'
# github access_token api
github_access_token_url = 'https://github.com/login/oauth/access_token'
# gitee 的 client id、 client secret、 redirect uri
gitee_client_id = '0dd3dc5d005a384d1e5dba633eabfdb59c6bc9d68df8eca374e3245e92156e40'
gitee_client_secret = 'you client secret'
gitee_redirect_uri = 'http://127.0.0.1:5000/oauth2/gitee/callback'
# gitee 用户信息api
gitee_user_info_url = 'https://gitee.com/api/v5/user'
# gitee access_token api
gitee_access_token_url = 'https://gitee.com/oauth/token'
def get_github_user_info(access_token):
"""
获取github用户信息
注意:github用户信息api,要求必须以请求头的形式传递token,不能以url方式传参
:param access_token:
:return:
"""
headers = {
'Authorization': f'token {access_token}'
}
print(github_user_info_url)
resp = requests.get(url=github_user_info_url, headers=headers)
if resp.status_code == 200:
return json.loads(resp.text)
else:
return {'msg': '认证失败'}
def get_gitee_user_info(access_token):
"""
获取gitee用户信息
:param access_token:
:return:
"""
resp = requests.get(url=gitee_user_info_url,
data={
'access_token': access_token
})
if resp.status_code == 200:
return json.loads(resp.text)
else:
return {'msg': '认证失败'}
def get_gitee_access_token(code):
"""
获取gitee的access token 该token用于向gitee请求用户信息
:param code:
:return:
"""
status = {'status': None, 'msg': None, 'data': ''}
try:
resp = requests.post(
url=gitee_access_token_url,
data={
'grant_type': 'authorization_code',
'client_id': gitee_client_id,
'client_secret': gitee_client_secret,
'code': code,
'redirect_uri': gitee_redirect_uri
}
)
if resp.status_code == 200:
status['status'] = True
status['msg'] = 'ok'
status['data'] = json.loads(resp.text).get('access_token')
except Exception as e:
status['status'] = False
status['msg'] = f'error:{e}'
return status
def get_github_access_token(code):
"""
获取github 的access token 用于向github获取用户信息
:param code:
:return:
"""
status = {'status': None, 'msg': None, 'data': ''}
try:
resp = requests.post(
url=github_access_token_url,
data={
'client_id': github_client_id,
'client_secret': github_client_secret,
'code': code,
}
)
if resp.status_code == 200:
status['status'] = True
status['msg'] = 'ok'
status['data'] = resp.content.decode('utf-8').split('&')[0].split('=')[1]
except Exception as e:
status['status'] = False
status['msg'] = f'error:{e}'
return status
@app.route('/login')
def login():
"""
登录接口
:return:
"""
print(f'https://github.com/login/oauth/authorize?client_id={github_client_id}&redirect_uri={github_redirect_uri}')
context = {
'github_auth_url': f'https://github.com/login/oauth/authorize?client_id={github_client_id}&redirect_uri={github_redirect_uri}',
'gitee_auth_url': f'https://gitee.com/oauth/authorize?client_id={gitee_client_id}&redirect_uri={gitee_redirect_uri}&response_type=code'
}
return render_template('login.html', context=context)
@app.route('/oauth2/github/callback')
def oauth_github_callback():
code = request.args.get('code')
print(f'github-code:{code}')
status = get_github_access_token(code)
print(status)
access_token = status.get('data')
github_user_info = get_github_user_info(access_token)
print(github_user_info)
jwt_payload = {
'user_id': github_user_info['id'],
'user_name': github_user_info['login'],
}
jwt = create_jwt(jwt_payload)
return render_template('index.html', user_info=github_user_info, jwt=jwt)
@app.route('/oauth2/gitee/callback')
def oauth_gitee_callback():
code = request.args.get('code')
print(f'gitee: {code}')
status = get_gitee_access_token(code)
access_token = status.get('data')
gitee_user_info = get_gitee_user_info(access_token)
print(gitee_user_info)
jwt_payload = {
'user_id': gitee_user_info['id'],
'user_name': gitee_user_info['login'],
}
jwt = create_jwt(jwt_payload)
return render_template('index.html', user_info=gitee_user_info, jwt=jwt)
def create_jwt(payload):
"""
生成token
:param payload: 需要jwt携带的参数
:return:
"""
# 构造header
headers = {
'typ': 'jwt',
'alg': 'HS256'
}
token = jwt.encode(payload=payload, key=app.secret_key, algorithm="HS256", headers=headers)
return token
def check_jwt(token):
status = {'status': None, 'msg': None}
try:
verified_payload = jwt.decode(jwt=token, key=app.secret_key, algorithms=['HS256'])
status['status'] = True
status['msg'] = verified_payload
except exceptions.ExpiredSignatureError:
status['msg'] = 'token已失效'
except jwt.DecodeError:
status['msg'] = 'token认证失败'
except jwt.InvalidTokenError:
status['msg'] = '非法的token'
return status
# 不需要验证token的白名单
WHITE_LIST = [
'/login',
'/oauth2/gitee/callback',
'/oauth2/github/callback',
]
@app.route('/source')
def source():
"""
资源接口
:return:
"""
return '资源列表'
@app.before_request
def check_jwt_hook():
"""
拦截请求,校验token是否合法
:return:
"""
# 如果请求路径在白名单内
if request.path in WHITE_LIST:
return
# 获取请求路径中的token
jwt = request.args.get('token')
if not jwt:
# 如果没有传递token,重定向到登录页面
return redirect('/login')
# 检验jwt
status = check_jwt(jwt)
if not status['status']:
print(status['msg'])
# 如果jwt校验失败还是重定向到登录页面
return redirect('/login')
# jwt校验成功直接到视图函数
return
if __name__ == '__main__':
app.run(debug=True)