Django学习笔记-AcApp端授权AcWing一键登录
笔记内容转载自 AcWing 的 Django 框架课讲义,课程链接:AcWing Django 框架课。
AcApp 端使用 AcWing 一键授权登录的流程与之前网页端的流程一样,只有申请授权码这一步有一点细微的差别:
我们在打开 AcApp 应用之后会自动向 AcWing 请求账号登录,客户端会向后端服务器请求一些参数,然后后端服务器向 AcWing 请求授权码,然后 AcWing 在接到请求之后会询问用户是否要授权登录,如果用户同意了那么 AcWing 会给客户端发送一个授权码,客户端可以通过授权码加上自己的身份信息向 AcWing 服务器请求自己的授权令牌 access_token
和用户的 openid
,最后客户端在拿到令牌和 ID 后即可向 AcWing 服务器请求用户的用户名和头像等信息。
在网页端授权登录时我们使用的方法是通过 URL 的方式重定向到某一个链接里申请授权码,而这次的 AcApp 不是通过链接,而是通过 AcWing 的一个 API 申请,请求授权码的 API:
AcWingOS.api.oauth2.authorize(appid, redirect_uri, scope, state, callback);
参数说明:
appid
:应用的唯一 ID,可以在 AcWing 编辑 AcApp 的界面里看到;redirect_uri
:接收授权码的地址,表示 AcWing 端要将授权码返回到哪个链接,需要对链接进行编码:Python3 中使用urllib.parse.quote
;Java 中使用URLEncoder.encode
;scope
:申请授权的范围,目前只需填userinfo
;state
:用于判断请求和回调的一致性,授权成功后原样返回该参数值,即接收授权码的地址需要判断是否是 AcWing 发来的请求(判断收到的state
与发送出去的state
是否相同),如果不是直接 Pass。该参数可用于防止 CSRF 攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数(如果是将第三方授权登录绑定到现有账号上,那么推荐用随机数 + user_id
作为state
的值,可以有效防止CSRF攻击)。此处state
可以存到 Redis 中,设置两小时有效期;callback
:redirect_uri
返回后的回调函数,即接受receive_code
函数向前端返回的信息。
用户同意授权后,会将 code
和 state
传递给 redirect_uri
。
如果用户拒绝授权,则将会收到如下错误码:
{errcode: "40010"errmsg: "user reject"
}
我们在 game/views/settings/acwing/acapp
目录中将之前网页端的 apply_code.py
与 receive_code.py
复制过来,然后对 apply_code.py
进行一点小修改,这次不是返回一个链接,而是返回四个参数:
from django.http import JsonResponse
from django.core.cache import cache
from urllib.parse import quote
from random import randintdef get_state(): # 获得8位长度的随机数res = ''for i in range(8):res += str(randint(0, 9))return resdef apply_code(request):appid = '4007'redirect_uri = quote('https://app4007.acapp.acwing.com.cn/settings/acwing/acapp/receive_code/')scope = 'userinfo'state = get_state()cache.set(state, True, 7200) # 有效期2小时# 需要返回四个参数return JsonResponse({'result': 'success','appid': appid,'redirect_uri': redirect_uri,'scope': scope,'state': state,})
进入 game/urls/settings/acwing
修改一下路由:
from django.urls import path
from game.views.settings.acwing.web.apply_code import apply_code as web_apply_code
from game.views.settings.acwing.web.receive_code import receive_code as web_receive_code
from game.views.settings.acwing.acapp.apply_code import apply_code as acapp_apply_code
from game.views.settings.acwing.acapp.receive_code import receive_code as acapp_receive_codeurlpatterns = [path('web/apply_code/', web_apply_code, name='settings_acwing_web_apply_code'),path('web/receive_code/', web_receive_code, name='settings_acwing_web_receive_code'),path('acapp/apply_code/', acapp_apply_code, name='settings_acwing_acapp_apply_code'),path('acapp/receive_code/', acapp_receive_code, name='settings_acwing_acapp_receive_code'),
]
现在访问 https://app4007.acapp.acwing.com.cn/settings/acwing/acapp/apply_code/
即可看到返回内容。
然后我们修改一下 receive_code.py
:
from django.http import JsonResponse
from django.core.cache import cache
from django.contrib.auth.models import User
from game.models.player.player import Player
from random import randint
import requestsdef receive_code(request):data = request.GETif 'errcode' in data:return JsonResponse({'result': 'apply failed','errcode': data['errcode'],'errmsg': data['errmsg'],})code = data.get('code')state = data.get('state')if not cache.has_key(state):return JsonResponse({'result': 'state not exist',})cache.delete(state)apply_access_token_url = 'https://www.acwing.com/third_party/api/oauth2/access_token/'params = {'appid': '4007','secret': '0edf233ee876407ea3542220e2a8d83e','code': code}access_token_res = requests.get(apply_access_token_url, params=params).json() # 申请授权令牌access_token = access_token_res['access_token']openid = access_token_res['openid']players = Player.objects.filter(openid=openid) # filter不管存不存在都会返回一个列表,get如果不存在会报异常if players.exists(): # 用户如果已存在就直接返回用户player = players[0]return JsonResponse({'result': 'success','username': player.user.username,'avatar': player.avatar,})get_userinfo_url = 'https://www.acwing.com/third_party/api/meta/identity/getinfo/'params = {'access_token': access_token,'openid': openid}get_userinfo_res = requests.get(get_userinfo_url, params=params).json() # 申请获取用户信息username = get_userinfo_res['username']avatar = get_userinfo_res['photo']while User.objects.filter(username=username).exists(): # 如果当前用户的用户名已经存在则在其后面添加若干位随机数username += str(randint(0, 9))user = User.objects.create(username=username) # 创建该用户,没有密码player = Player.objects.create(user=user, avatar=avatar, openid=openid)return JsonResponse({'result': 'success','username': player.user.username,'avatar': player.avatar,})
接着我们修改前端文件,也就是 game/static/js/src/settings
目录中的 Settings
类:
class Settings {constructor(root) {this.root = root;this.platform = 'WEB'; // 默认为Web前端if (this.root.acwingos) this.platform = 'ACAPP';this.username = ''; // 初始用户信息为空this.avatar = '';this.$settings = $(`...`);...this.start();}start() { // 在初始化时需要从服务器端获取用户信息if (this.platform === 'WEB') {this.getinfo_web();this.add_listening_events();} else {this.getinfo_acapp();}}add_listening_events() { // 绑定监听函数...}add_listening_events_login() {...}add_listening_events_register() {...}login_on_remote() { // 在远程服务器上登录...}register_on_remote() { // 在远程服务器上注册...}acwing_login() {...}register() { // 打开注册界面...}login() { // 打开登录界面...}getinfo_web() { // 此处将之前的getinfo函数名进行了修改用来区分let outer = this;$.ajax({url: 'https://app4007.acapp.acwing.com.cn/settings/getinfo/', // 用AcWing部署// url: 'http://8.130.54.44:8000/settings/getinfo/', // 用云服务器部署type: 'GET',data: {platform: outer.platform,},success: function(resp) { // 调用成功的回调函数,返回的Json字典会传给respconsole.log(resp); // 控制台输出查看结果if (resp.result === 'success') {outer.username = resp.username;outer.avatar = resp.avatar;outer.hide();outer.root.menu.show();} else { // 如果未登录则需要弹出登录界面outer.login();}}});}acapp_login(appid, redirect_uri, scope, state) {let outer = this;// resp是redirect_uri的返回值,此处为用户名和头像this.root.acwingos.api.oauth2.authorize(appid, redirect_uri, scope, state, function(resp) {console.log(resp);if (resp.result === 'success') {outer.username = resp.username;outer.avatar = resp.avatar;outer.hide();outer.root.menu.show();}});}getinfo_acapp() {let outer = this;$.ajax({url: 'https://app4007.acapp.acwing.com.cn/settings/acwing/acapp/apply_code/',type: 'GET',success: function(resp) {if (resp.result === 'success') {outer.acapp_login(resp.appid, resp.redirect_uri, resp.scope, resp.state);}}});}hide() {this.$settings.hide();}show() {this.$settings.show();}
}
注意,如果遇到跨域问题:Access to XMLHttpRequest at 'XXX'
,大概率是某个文件的内容写错了,可以检查 uWSGI 启动后的报错内容修改代码。
相关文章:

Django学习笔记-AcApp端授权AcWing一键登录
笔记内容转载自 AcWing 的 Django 框架课讲义,课程链接:AcWing Django 框架课。 AcApp 端使用 AcWing 一键授权登录的流程与之前网页端的流程一样,只有申请授权码这一步有一点细微的差别: 我们在打开 AcApp 应用之后会自动向 AcW…...

如何在小红书进行学习直播
诸神缄默不语-个人CSDN博文目录 因为我是从B站开始的,所以一些直播常识型的东西请见我之前写的如何在B站进行学习直播这一篇。 本篇主要介绍一些小红书之与B站不同之处。 小红书在手机端是可以直接点击“”选择直播的。 文章目录 1. 电脑直播-小红书直播软件2. 电…...

F5服务器负载均衡能力如何?一文了解
但凡知道服务器负载均衡这个名词的,基本都知道 F5,因为负载均衡是 F5 的代表作,换句话来说,负载均衡就是由 F5 发明的。提到F5服务器负载均衡能力如何?不得不关注F5提出的关于安全、网络全面优化的解决方案,…...

Ubuntu18.04安装docker-io
1. 安装docker 1.1 网上一搜,全是更新仓库、下载依赖、添加docker的gpg密钥、添加docker仓库、安装docker-ce的步骤,但是在安装docker-ce时却提示“package "docker-ce" has no installation candidate”,就很迷。 1.2 安装docke…...

代码随想录笔记--栈与队列篇
目录 1--用栈实现队列 2--用队列实现栈 3--有效的括号 4--删除字符串中的所有相邻重复项 5--逆波兰表达式求值 6--滑动窗口的最大值 7--前k个高频元素 1--用栈实现队列 利用两个栈,一个是输入栈,另一个是输出栈; #include <iostrea…...
【力扣】55. 跳跃游戏 <贪心>
【力扣】55. 跳跃游戏 给一个非负整数数组 nums ,最初位于数组的第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。 示例 1…...

在iPhone 15发布之前,iPhone在智能手机出货量上占据主导地位,这对安卓来说是个坏消息
可以说这是一记重拳,但似乎没有一个有价值的竞争者能与苹果今年迄今为止的智能手机出货量相媲美。 事实上,根据Omdia智能手机型号市场跟踪机构收集的数据,苹果的iPhone占据了前四名。位居榜首的是iPhone 14 Pro Max,2023年上半年…...
题目:2620.计数器
题目来源: leetcode题目,网址:2620. 计数器 - 力扣(LeetCode) 解题思路: 定义两个全局变量,一个判断 n 是否改变,另一个记录上一次出现的数。 解题代码: /*** par…...
【MySQL】MySQL系统变量(system variables)列表(SHOW VARIABLES 的结果例)
文章目录 【MySQL】MySQL系统变量(system variables)列表(SHOW VARIABLES 的结果例)SHOW VARIABLES 的结果例参考 【免责声明】文章仅供学习交流,观点代表个人,与任何公司无关。 编辑|SQL和数据库技术(ID:S…...
【多AZ】浅述云计算多az
多AZ(Availability Zone)是云计算中一种重要的容灾和冗余策略,它通过在不同的地理位置或不同的设备上存储数据副本以及网络切换策略,以保证在单个设备或地理位置发生故障时,云加计算集群仍然能够提供服务。 多AZ的特点…...
Element浅尝辄止13:Collapse 折叠面板
通过折叠面板收纳内容区域 1.如何使用? 可同时展开多个面板,面板之间不影响 <el-collapse v-model"activeNames" change"handleChange"><el-collapse-item title"一致性 Consistency" name"1">&l…...
51 单片机包含头文件 BIN51.H 直接写二进制数字
51 单片机包含头文件 BIN51.H 直接写二进制 最近学习 51 单片机,写代码的时候感觉用二进制的形式更直观。就是每次都需要宏定义,太麻烦。干脆把所有的8位二进制数字全部用宏定义写出来,放进头文件,下次使用直接包含头文件就行。 …...

php环境搭建步骤(与资源配套使用版)
1.将phpEnv.zip下载到D盘下 2.解压到当前文件夹 3.找到Apache24下的bin目录,执行cmd操作,回车。 4.在cmd中执行代码 Httpd -k install -n “Apache24” 4.使用winR键打开运行,输入services.msc ,回车,进入服务 …...
java 集合处理:
// 1 数组转map public static void main(String[] args) {String backendIdStr"[\"backend-mvj05upv7yc\",\"backend-mvj055qvric\",\"backend-mvj04hlutx4\"]";String[] backendIdList JsonUtil.asObject(backendIdStr, String[].c…...
算法训练第五十二天
718. 最长重复子数组 - 力扣(LeetCode) class Solution { public:int findLength(vector<int>& nums1, vector<int>& nums2) {vector<vector<int>> dp(nums1.size() 1,vector<int>(nums2.size() 1,0));int res…...

LeetCode——回溯篇(三)
刷题顺序及思路来源于代码随想录,网站地址:https://programmercarl.com 目录 46. 全排列 47. 全排列 II 332. 重新安排行程 51. N 皇后 37. 解数独 46. 全排列 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任…...

Python爬取京东商品评论
寻找数据真实接口 打开京东商品网址查看商品评价。我们点击评论翻页,发现网址未发生变化,说明该网页是动态网页。 API名称:item_review-获得JD商品评论 公共参数 获取API测试key&secret 名称类型必须描述keyString是调用keyÿ…...

ROS机器人编程---------(一)安装ROS
安装ROS 打开终端按顺序执行下面命令 默认安装在/opt/ros路径下 打开一个终端输入roscore 测试是否安装成功 启动ROS Master roscore启动小海龟仿真器 rosrun turtlesim turtlesim_node启动海龟控制结点 rosrun turtlesim turtlesim_teleop_key使用键盘方向键控…...

Maven入门教程(一):安装Maven环境
视频教程:Maven保姆级教程 Maven入门教程(一):安装Maven环境 Maven入门教程(二):idea/Eclipse使用Maven Maven入门教程(三):Maven语法 Maven入门教程(四):Nexus私服 Maven入门教程(五):自定义脚手架 Maven项…...
CSS中可继承与不可继承属性
可继承 1. 字体属性: font、font-style、font-variant、font-weight、font-size、line-height等属性是字体样式的属性,都可以被子元素继承。 2. 文本属性: color、text-indent、text-align、text-decoration、text-transform、letter-spa…...

XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...

测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...

LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...
es6+和css3新增的特性有哪些
一:ECMAScript 新特性(ES6) ES6 (2015) - 革命性更新 1,记住的方法,从一个方法里面用到了哪些技术 1,let /const块级作用域声明2,**默认参数**:函数参数可以设置默认值。3&#x…...

数据结构第5章:树和二叉树完全指南(自整理详细图文笔记)
名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪) 原创笔记:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 上一篇:《数据结构第4章 数组和广义表》…...