当前位置: 首页 > news >正文

Python3 - Flask+swift实现单点登录

基于 Flask 和 Redis 实现单设备登录的服务端代码和客户端swift、oc代码:

Python flask 实现服务端

from flask import Flask, jsonify, request
from redis import Redisapp = Flask(__name__)
redis_db = Redis()# 用户登录接口,验证用户名和密码,生成并保存 token 到 Redis 中
@app.route('/login', methods=['POST'])
def login():username = request.json.get('username')password = request.json.get('password')# 验证用户身份if check_user(username, password):# 生成 token 并存储到 Redis 中token = generate_token()redis_db.set(token, username)redis_db.expire(token, 1800)  # 设置过期时间为 30 分钟return jsonify({'token': token}), 200return 'Invalid username or password', 401# 业务逻辑接口,需要校验 token 
@app.route('/api/xxx', methods=['GET'])
def api_xxx():token = request.headers.get('Authorization')if not token or not token.startswith('Bearer '):return 'Missing or invalid token', 401# 提取 token 值token = token.split(' ')[1]# 检查 token 是否合法和未过期if redis_db.exists(token):redis_db.expire(token, 1800)  # 续约 token 的过期时间return 'Business logic here', 200return 'Invalid token', 401def check_user(username, password):# TODO: 进行用户身份验证return Truedef generate_token():# TODO: 生成唯一且安全的 tokenreturn 'random_token'if __name__ == '__main__':app.run(debug=True)

在服务端 Python 应用程序中,需要注意以下几点:

  1. 通过 Flask-Redis 扩展连接到 Redis 数据库。可以使用 redis.StrictRedis() 或者 redis.Redis.from_url() 方法创建 Redis 实例。
  2. 在登录接口和业务逻辑接口中添加 token 的校验代码,如果 token 不合法或已过期,则返回 401 状态码。
  3. 在业务逻辑接口中,需要从请求头 Authorization 中提取出 token 值,并检查其是否以 "Bearer " 开头。需要对提取 token 的代码进行安全性检查,防止恶意修改请求头信息。

需要注意的是,上述代码只是一个示例,实际操作时需要进一步完善和优化,例如加入数据验证、错误处理等功能。同时,还需要考虑如何保护敏感数据不被泄露,例如使用 HTTPS 协议、存储密码的哈希值等措施。

客户端为 Swift 语言实现:

import UIKitclass LoginViewController: UIViewController {// 用户名和密码输入框@IBOutlet weak var usernameTextField: UITextField!@IBOutlet weak var passwordTextField: UITextField!override func viewDidLoad() {super.viewDidLoad()}@IBAction func loginButtonTapped(_ sender: Any) {let baseUrl = "https://example.com"let loginUrl = URL(string: "\(baseUrl)/login")!// 创建请求对象var request = URLRequest(url: loginUrl)request.httpMethod = "POST"request.addValue("application/json", forHTTPHeaderField: "Content-Type")// 添加请求体内容let parameters = ["username": usernameTextField.text ?? "","password": passwordTextField.text ?? ""]do {let jsonData = try JSONSerialization.data(withJSONObject: parameters, options: [])request.httpBody = jsonData} catch {print(error.localizedDescription)}// 发送登录请求let task = URLSession.shared.dataTask(with: request) { (data, response, error) inif let error = error {print(error.localizedDescription)return}guard let httpResponse = response as? HTTPURLResponse else {print("Invalid response type")return}if 200...299 ~= httpResponse.statusCode,let data = data,let token = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: String],let authToken = token["token"] {// 登录成功,保存 token 到 Keychain 中self.saveTokenToKeychain(authToken)DispatchQueue.main.async {// 切换到主线程,跳转到下一个页面self.performSegue(withIdentifier: "ShowBusinessLogicSegue", sender: nil)}} else {// 登录失败,显示错误提示DispatchQueue.main.async {let alertController = UIAlertController(title: "Login Failed", message: "Invalid username or password.", preferredStyle: .alert)let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)alertController.addAction(okAction)self.present(alertController, animated: true, completion: nil)}}}task.resume()}func saveTokenToKeychain(_ token: String) {// TODO: 将 token 保存到 Keychain 中}
}class BusinessLogicViewController: UIViewController {override func viewDidLoad() {super.viewDidLoad()}@IBAction func doSomethingButtonTapped(_ sender: Any) {let baseUrl = "https://example.com"let apiUrl = URL(string: "\(baseUrl)/api/xxx")!// 创建请求对象var request = URLRequest(url: apiUrl)request.httpMethod = "GET"// 添加请求头 Authorizationif let authToken = getTokenFromKeychain() {request.addValue("Bearer \(authToken)", forHTTPHeaderField: "Authorization")} else {print("Missing auth token")return}// 发送业务逻辑请求let task = URLSession.shared.dataTask(with: request) { (data, response, error) inif let error = error {print(error.localizedDescription)return}guard let httpResponse = response as? HTTPURLResponse else {print("Invalid response type")return}if 200...299 ~= httpResponse.statusCode {// 处理业务逻辑print("Business logic here")} else if httpResponse.statusCode == 401 {// token 过期或者无效,跳转到登录页面重新登录DispatchQueue.main.async {self.navigationController?.popToRootViewController(animated: true)}} else {// 接口返回错误print("API error")}}task.resume()}func getTokenFromKeychain() -> String? {// TODO: 从 Keychain 中获取 tokenreturn nil}
}

在客户端 Swift 应用程序中,需要注意以下几点:

  1. 发送登录请求时,需要将用户名和密码转换为 JSON 格式的字符串,并设置请求头 Content-Type 为 application/json。
  2. 在登录成功后,需要将服务器返回的 token 保存到 Keychain 中,以便在下一次请求时使用。
  3. 发送业务逻辑请求时,需要在请求头 Authorization 中添加上保存的 token 值(Bearer {token})。

客户端 Objective-C 实现

在客户端 Objective-C 应用程序中,需要在每次发起请求时添加请求头信息(Authorization),包含存储的 token 值。具体实现可以参考以下示例代码:

// 发送登录请求
NSString *url = @"http://example.com/login"
NSDictionary *parameters = @{@"username": @"your_username", @"password": @"your_password"};
[[AFHTTPSessionManager manager] POST:url parameters:parameters success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {// 登录成功,将会话标识符保存至本地存储NSString *sessionId = responseObject[@"sessionId"];[[NSUserDefaults standardUserDefaults] setObject:sessionId forKey:@"sessionId"];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {// 登录失败
}];NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/api/xxx"]];
[request setValue:@"Bearer {token}" forHTTPHeaderField:@"Authorization"];
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {// 处理返回数据
}];
[task resume];

需要注意的是,上述代码中 {token} 部分需要替换为从登录接口获取到的有效 token 值。

补充:定期删除redis过期token

要清理过期的 Token,您可以使用 Python 中的定时任务库(例如 APSchedulerschedule)来定期检查并删除过期 Token。以下是一个示例:

import datetime
import threadingTOKEN_EXPIRATION_TIME = 1800  # Token 过期时间(秒)
tokens = {}  # 存储 Token 的字典def clear_expired_tokens():"""删除过期的 Token"""now = datetime.datetime.now().timestamp()expired_tokens = [token for token, timestamp in tokens.items() if now - timestamp > TOKEN_EXPIRATION_TIME]for token in expired_tokens:del tokens[token]threading.Timer(TOKEN_EXPIRATION_TIME, clear_expired_tokens).start()def generate_token():"""生成 Token"""token = str(uuid.uuid4())tokens[token] = datetime.datetime.now().timestamp()return token# 启动定时任务
clear_expired_tokens()

在这个示例中,我们首先定义了一个存储 Token 的字典 tokens,以及 Token 的过期时间 TOKEN_EXPIRATION_TIME。然后,我们定义了一个函数 clear_expired_tokens(),该函数会定期检查 tokens 字典中的 Token 是否已过期,并将过期的 Token 从字典中删除。

接下来,我们定义了一个生成 Token 的函数 generate_token(),该函数生成随机的 UUID 并将其作为键存储到 tokens 字典中,并将当前时间戳作为值存储。最后,我们使用 threading.Timer 启动一个定时任务,以便每隔 TOKEN_EXPIRATION_TIME 秒调用一次 clear_expired_tokens() 函数。

请注意,这只是一个示例实现,您可以根据自己的需求进行修改和优化。例如,如果您的应用程序使用数据库存储 Token,则可以考虑在数据库层面上清理过期 Token。

相关文章:

Python3 - Flask+swift实现单点登录

基于 Flask 和 Redis 实现单设备登录的服务端代码和客户端swift、oc代码: Python flask 实现服务端 from flask import Flask, jsonify, request from redis import Redisapp Flask(__name__) redis_db Redis()# 用户登录接口,验证用户名和密码&#…...

HTML URL

文章目录HTML URLURL - 统一资源定位器常见的 URL SchemeURL 字符编码URL 编码实例HTML URL URL 是一个网页地址。 URL可以由字母组成,如"csdn.net",或互联网协议(IP)地址: 192.168.100.1。大多数人进入网站…...

带你了解ICCV、ECCV、CVPR三大国际会议

文章目录 前言 一、ICCV、ECCV、CVPR是什么? 1.ICCV 2.ECCV 3.CVPR 二、三大会链接及论文下载链接 前言  作为刚入门CV的新人,有必要记住计算机视觉方面的三大顶级会议:ICCV,CVPR,ECCV,统称为ICE。 与其它学术领域不同,计算机科学使用会议而不是期刊作为发表研究成果的主…...

常用的一些代码

今天菜鸟涨工资了,到手估计有8000左右了,有点开心,本来想上一篇就把这篇写了的,但是发现还是分开写比较好! 文章目录自适应js禁止放大播放声音store的使用websocket封装echarts实现渐变swiper常用的陌生方法&#xff0…...

Python-df.pop()和np.array.shape()属性

1.df.pop() 删除某一列 可以使用这个来删除某一列(不能是多列),只有一个参数,就是列名,可以是str类型,函数返回的是被删除的列,df直接是删除后的df,不需要我们处理。 我们建模时&a…...

多线程并发编程笔记03(小滴课堂)---线程安全性

原子性操作: 这样一段代码。 我们输出一下: 我们发现它的结果和我们想的不太一样。 正常应该输出1000. 这是因为没有保证原子性。 所以我们来加上原子性: 这样就保证了我们的原子性。 接下来我们来细说说这个关键字: 我发现我…...

提升代码质量,使用插件对 java 代码进行扫描检查分析

目录前言一、使用maven-checkstyle-plugin插件1. maven-checkstyle-plugin 介绍2.引入依赖3.使用二、使用 idea 插件1.安装2.使用前言 很多时候我们的代码写的不规范,比如没缩进、参数间没空格、导入的包没用到没删除、方法很长没有进行拆分、 直接对方法参数进行了…...

如何用秒验提升用户体验和转换率?

手机号验证是移动应用开发中常见的需求,它可以用于用户注册、登录、身份认证等场景。目前,市场上主要的手机号验证方式是短信验证码,但这种方式存在一些问题,例如: 延迟:短信验证码需要等待运营商发送和用…...

【新】(2023Q2模拟题JAVA)华为OD机试 - 机器人活动区域

最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧本篇题解:机器人活动区域 题目 现有一…...

2023软件测试面试真题宝典大汇总,没收藏的都后悔了

下边是我根据工作这几年来的面试经验,加上之前收集的资料,整理出来350道软件测试工程师 常考的面试题。字节跳动、阿里、腾讯、百度、快手、美团等大厂常考的面试题,在文章里面都有提到。 虽然这篇文章很长,但是绝对值得你点击一…...

十、MyBatis的逆向工程

一、MyBatis的逆向工程 正向工程:先创建java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源: Java实体类 Mapper接口 Mapper映射文件 1.创…...

网站是怎么屏蔽脏话的呢:简单学会SpringBoot项目敏感词、违规词过滤方案

一个社区最重要的就是交流氛围与审查违规,而这两者都少不了对于敏感词进行过滤的自动维护措施。基于这样的措施,我们才能基本保证用户在使用社区的过程中,不至于被敏感违规词汇包围,才能够正常的进行发布帖子和评论,享…...

kafka经典面试题

这里写目录标题1.生产者1.1 生产者发送原理1.2 分区有什么好处?1.3 生产消息时, 是如何决定消息落盘到哪个分区的?1.4 生产者如何提高吞吐量1.5 如何保证生产的消息不丢失(能成功落盘)1.6 ack为-1, 就肯定不会丢失数据吗?1.7 生产者重复发送消息的场景1.8 生产者如何保证数据…...

我的CSDN笔记总索引(阅读量降序,代码自动遍历生成HTML5源码)

Python代码用Linux命令行工具crul获取CSDN博文页面源码,Python内置re正则解析出博文笔记信息。 (本文获得CSDN质量评分【xx】)【学习的细节是欢悦的历程】Python 官网:https://www.python.org/ Free:大咖免费“圣经”教程《 python 完全自学…...

修改Windows hosts文件的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...

愤怒的Spring(三)Idaea Maven搭建Spring并运行项目(超详细,超全)

愤怒的Spring(三) 一、目录结构 环境搭配与上一篇内容一样,详情请看愤怒的Spring(二)Idaea Maven搭建Spring并运行项目(超详细,超全)https://blog.csdn.net/sz710211849/article/d…...

NDK(三):JNIEnv解析

文章目录一、概述二、JNIEnv结构体三、JNINativeInterface结构体3.1 Class操作3.2 反射操作3.3 对象字段 & 方法操作3.4 类的静态字段 & 静态方法操作3.5 字符串操作3.6 锁操作3.7 数组操作3.8 注册和反注册native方法3.9 异常Exception操作3.10 引用的操作3.11 其它四…...

禅道——图文安装及使用教程

👨‍💻作者简介:练习时长两年半的java博主 📖个人主页:君临๑ 🎞️文章介绍:禅道的2023版安装图文教程 🎁 如果文章对你有用,就点个免费的赞吧👍 目录 一、搜…...

Java基础——枚举类enum

枚举类是一种特殊的数据类型,可以理解为一个数组,数组成员为特定的对象枚举类不能在外面创建对象,在类里面就包含了一组特定的对象,每个对象有着相同数量的属性枚举类的对象放在最前面,且对象们的顺序就是对应的索引枚…...

【机器学习】一文了解如何评估和选择最佳机器学习模型并绘制ROC曲线?

一文了解如何评估和选择最佳机器学习模型? 问ChatGPT:如何选择最佳机器学习模型?问ChatGPT:评估机器学习模型有哪些指标?0. 引言1. 混淆矩阵2. 评价指标3. ROC与AUC4. PR(precision recall )曲线参考资料问ChatGPT:如何选择最佳机器学习模型? 选择最佳机器学习模型是机…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...