前一节:用户名密码登录(详细操作步骤)https://www.acwing.com/blog/content/33461/
NoSQL 数据库 Redis
Redis 是一个内存数据库,运行速度快,单线程执行任务,线程安全。
存储形式:K-V 键值对。
在 Django 中集成 Redis
1、安装 django_redis
pip install django_redis
2、在 settings.py
中配置 Redis
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
},
},
}
USER_AGENTS_CACHE = 'default'
3、启动 redis-server
sudo redis-server /etc/redis/redis.conf
如何使用 Redis
在项目根目录 acapp
下打开交互式 shell 可以操作 Redis
python3 manage.py shell
使用时需要导入 cache
,通过 cache 操作执行 redis 命令
from django.core.cache import cache
常用命令有:
# 查找 redis 中所有的 key,括号内支持正则表达式
cache.keys('*')
# 存储一个键值对 [tonngw, 1],5 表示过期时间(s)
# 将第三个参数设置为 None 则该数据不会过期
cache.set('tonngw', 1, 5)
# 判断某个 key 是否存在
cache.has_key('tonngw')
# 查询 key 对应的值
cache.get('tonngw')
# 通过 key 删除一个 key-value 键值对
cache.delete('tonngw')
AcWing 授权登录的流程
AcWing API 文档:https://www.acwing.com/blog/content/12466/
第一步:申请授权码 code
完善 Player 类,添加 openid 字段,是一个 32 位的字符串。
openid = models.CharField(default="", max_length=50, blank=True, null=True)
在 views/settings
目录下创建 acwing
,在 acwing
目录下分别创建 web
端和 acapp
端两个目录,每个目录要想被 import 记得创建 __init__.py
。
回到 web 端开始实现第一步,向 acwing 申请授权码 code,返回的是一个授权登录页面的链接。
apply_code.py
:获取授权码
from django.http import JsonResponse
from urllib.parse import quote
from random import randint
from django.core.cache import cache
def get_state():
res = ""
for i in range(8):
res += str(randint(0, 9))
return res
def apply_code(request):
appid = "2306"
redirect_uri = quote("https://app2306.acapp.acwing.com.cn/settings/acwing/web/receive_code") # recode for url, replace special char, eg: ':、?、&' etc.
scope = "userinfo"
state = get_state() # generate a 8bit random string, avoid other user attack our website
cache.set(state, True, 7200) # state expire time 2h
apply_code_url = "https://www.acwing.com/third_party/api/oauth2/web/authorize/"
return JsonResponse({
'result': "success",
'apply_code_url': apply_code_url + "?appid=%s&redirect_uri=%s&scope=%s&state=%s" % (appid, redirect_uri, scope, state),
})
receive_code.py
:接受授权码的地址处理函数
from django.shortcuts import redirect
from django.core.cache import cache
def receive_code(request): # 接受授权码的地址 | receive code address
data = request.GET
code = data.get('code')
state = data.get('state')
if not cache.has_key(state): # if the request state is not exist redis, it is a attack from other server
return redirect("index")
# after authenticate success
cache.delete(state) # delete state key, guarantee one state for one authenticate
return redirect("index")
不要忘了路由配置~
修复 getinfo.py
将原来获取第一个用户的信息改成获取当前登录用户的信息
player = Player.objects.get(user=user) # get current login user info
后端接口调试通过后,开始写前端 js 逻辑
settings/zbase.js
,添加 acwing 一键登录到 acwing 授权登录页面。
add_listening_events() {
let outer = this;
...
// 监听 acwing 一键登录添加点击事件
this.$acwing_login.click(function() { // add click listening events for acwing login img
outer.acwing_login();
});
}
acwing_login() {
// 访问申请授权码 url 申请 AcWing 授权
$.ajax({
url: "https://app2306.acapp.acwing.com.cn/settings/acwing/web/apply_code/",
type: "GET",
success: function(resp) {
console.log(resp);
if (resp.result === "success") { // request success redirect to apply_code_url authenticate page
window.location.replace(resp.apply_code_url);
}
}
});
}
点击之后的实现效果就是打开 AcWing 的授权登录页面
第二步:申请授权令牌 access_token
和用户的 openid
继续在 receive_code()
函数中执行下面的流程,向指定 api 发送请求获取信息。
import requests
def receive_code(request):
...
apply_access_token_url = "https://www.acwing.com/third_party/api/oauth2/access_token/"
params = {
'appid': "2306",
'secret': "**************************",
'code': code
}
# return a json data
access_token_res = requests.get(apply_access_token_url, params).json() # send a get request to url use requests lib
...
第三步:申请用户信息
继续完成向AcWing 申请用户信息
from django.contrib.auth.models import User
from game.models.player.player import Player
from django.contrib.auth import login
from random import randint
def receive_code(request):
...
access_token = access_token_res['access_token']
openid = access_token_res['openid']
players = Player.objects.filter(openid=openid)
if players.exists(): # 如果该用户已存在,则无需从 AcWing 重新获取用户信,直接登录即可 | if the user already exists, you dont need to get the user info from acwing again, just login.
login(request, players[0].user)
return redirect("index")
get_userinfo_url = "https://www.acwing.com/third_party/api/meta/identity/getinfo/"
params = {
"access_token": access_token,
"openid": openid,
}
userinfo_res = requests.get(get_userinfo_url, params=params).json();
username = userinfo_res['username']
photo = userinfo_res['photo']
while User.objects.filter(username=username).exists(): # get a not existed username
username += str(randint(0, 9))
user = User.objects.create(username=username) # create user and save db
player = Player.objects.create(user=user, photo=photo, openid=openid) # create player and save db
login(request, user)
...
实现效果
实现效果就是当用户点击AcWing一键登录后会获取用户的信息,授权成功后会自动登录,开始游戏便会显示自己的头像,同时会自动保存当前用户的信息到数据库中,openid 字段会被赋值,授权成功后一个月内不需要再次授权。
由于我之前使用的就是自己的头像,那么可以从后台查看 openid 已经有值了,同时帮我重新生成了一个不重复的用户名。