【Django+Vue3 线上教育平台项目实战】登录功能模块之短信登录与钉钉三方登录

在这里插入图片描述


文章目录

  • 前言
  • 一、几个关键概念
    • 1.HTTP无状态性
    • 2.Session机制
    • 3.Token认证
    • 4.JWT
  • 二、通过手机号验证码登录
    • 1.前端短信登录界面
    • 2.发送短信接口与短信登录接口
    • 3.Vue 设置interceptors拦截器
    • 4. 服务端验证采用自定义中间件方式实现
    • 5. 操作流程及效果图如下:
  • 三、通过第三方平台进行登录
    • 1.准备工作
    • 2.前端钉钉登录界面
    • 3.后端逻辑处理
    • 4.操作流程及效果图如下:


前言

    在当今的数字化时代,用户认证是任何在线服务安全性的基石。本文将简明扼要地介绍登录注册流程中的核心概念:HTTP无状态性、Session、Token与JWT,并详细阐述两种实用登录方式—— 手机号登录验证(借助容联云/云通讯服务)钉钉第三方登录。我们将探讨这些概念的基本原理,并深入解析两种登录方式的实现流程,旨在帮助开发者提升用户认证的安全性与便捷性。


一、几个关键概念

    首先,我们来分析登录注册流程中涉及的几个关键概念及其工作机制,特别是关于HTTP无状态性、Session机制、Token认证,以及它们如何影响 单点登录(SSO) 的实现。

1.HTTP无状态性

    HTTP协议本身是无状态的,这意味着服务器不会保留来自先前请求的客户端信息。每次请求都被视为完全独立的,服务器不会记住之前发生了什么。正是由于HTTP的无状态性,服务器无法直接记住用户是否已经登录或注册。这意味着每次用户请求都需要重新验证用户的身份,这在没有额外机制的情况下是不可行的。这种设计虽然简化了服务器的实现,但也要求开发者实现一些机制来跟踪用户会话和状态。

2.Session机制

工作原理:

  • 1. 请求发起:客户端(如浏览器)向服务器发起请求。
  • 2. 验证与生成Session:服务器验证请求(如登录验证),验证通过后,在服务器上创建一个Session对象,并为其分配一个唯一的标识符(如JSESSIONID)。这个Session对象可以存储用户的信息,如用户名、权限等。
  • 3. 返回Session ID:服务器将JSESSIONID作为响应的一部分(通常通过Set-Cookie头部)发送给客户端。
  • 4. 客户端存储:客户端(浏览器)将JSESSIONID存储在Cookie中。
  • 5. 后续请求:在后续的请求中,客户端会自动将JSESSIONID包含在请求头(如Cookie)中发送给服务器。
  • 6. 验证Session:服务器通过JSESSIONID在服务器上查找对应的Session对象,如果找到,则继续处理请求;如果未找到,则可能表示用户未登录或Session已过期。

不适合单点登录的原因:

  • 每个应用或服务都可能有自己的Session管理机制,这使得跨多个应用或服务共享登录状态变得复杂。

3.Token认证

工作原理:

  • 1.请求发起:客户端向服务器发起请求(如登录请求)。
  • 2.验证与生成Token:服务器验证请求(如用户名和密码),验证通过后,生成一个唯一的Token(通常是一个加密的字符串),并将其存储在数据库中(或缓存中)。
  • 3.返回Token:服务器将Token作为响应的一部分发送给客户端。
  • 4.客户端存储:客户端将Token存储在Cookie、LocalStorage或SessionStorage中(取决于具体实现和安全需求)。
  • 5.后续请求:在后续的请求中,客户端将Token包含在请求头(如Authorization: Bearer )中发送给服务器。
  • 6.验证Token:服务器通过查询数据库(或缓存)来验证Token的有效性,如果Token有效,则继续处理请求。

适合单点登录的原因:

  • Token可以在多个应用或服务之间共享,只要它们能够访问存储Token的数据库或缓存。
  • 通过适当的认证服务器(如OAuth2.0中的授权服务器),可以实现跨域的单点登录。

4.JWT

    JWT(JSON Web Token) 是一种无状态的Token认证机制,它允许服务器在Token中直接包含用户的身份信息和其他必要的验证信息。客户端在每次请求时携带这个Token,服务器通过验证Token来识别用户的身份和权限。

JWT的组成部分:
JWT由三部分组成:头部(Header)、载荷(Payload)和签名(Signature),每一部分都通过Base64编码后进行传输。

  • 头部(Header):包含了令牌的元数据,如令牌的类型(JWT)和所使用的签名算法(如HMAC SHA256或RSA)。
  • 载荷(Payload):包含了实际要传输的用户信息和其他元数据。这些信息可以是用户的姓名、角色、权限、到期时间等。载荷是JWT的主体部分,用于传递用户信息。
  • 签名(Signature):用于验证JWT的完整性和真实性。签名通过对头部和载荷进行哈希运算,并使用私钥(在生成JWT时)或公钥(在验证JWT时)进行加密生成。接收者可以使用公钥对签名进行解密,从而验证JWT的真实性和来源。
  • 加密: base64(头部).base64(载荷).HS256(base64(头部).base64(载和),‘盐’)
  • 解密: HS256(base64(头部).base64(载荷),‘盐’) 生成一个新的签名和传递过来的签名进行对比

根据上述内容,我们可以构建一个简单的jwt工具类用于jwt的加密解密:

from fuguang_back.settings import SECRET_KEY
import jwt
import timeclass MyJwt():def __init__(self):self.secret = SECRET_KEY# 加密def jwt_encode(self, payload):# 载荷、盐、加密方式return jwt.encode(payload, self.secret, algorithm='HS256')# 解密def jwt_decode(self, token):# token,盐、解密方式return jwt.decode(token, self.secret, algorithms=['HS256'])mjwt = MyJwt()
# user = {"id":1,"name":"zhangsan","exp":int(time.time()) + 3600}
# token = mjwt.jwt_encode(user)
# print(token)
# token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwibmFtZSI6InpoYW5nc2FuIiwiZXhwIjoxNzE5OTI0OTQ5fQ.rTPpHAx-92Pz1CmoRdO-yfGlAhAfuMInju2bFi1iixs"
# data = mjwt.jwt_decode(token)
# print(data)
# {'id': 1, 'name': 'zhangsan', 'exp': 1719924949}

二、通过手机号验证码登录

手机号登录流程:

  • 1.在登录界面输入手机号,点击发送验证码
  • 2.写一个发送验证码的接口,获取手机号(正则有效性验证),限制一分钟内只能发一次,查询redis中是否存在,如果存在返回已经发过,不存在调用发送,发送成功后存入redis
  • 3.用户输入验证码点击登录
  • 4.写一个登录接口
    • 获取用户输入的手机号和验证码
    • 通过手机号查询redis获取验证码,如果存在,则对比验证码
    • 通过手机号查询用户表,如果存在获取用户信息生成 jwt token,如果不存在,写入用户表,用户信息生成 jwt token返回给客户端
  • 5.客户端把token存在 localStorage中,以后每次请求在头部携带token。vue设置 interceptors拦截器,对每次请求前统一在头部加token
  • 6.服户端验证采用中间件方式实现。自定义中间件,继承MiddiwareMinxin类重写process_request.方法中
    • 定义白名单,在登录前需要操作的接口放到白名单中
      • 如果不在白名单,获取token,验证
      • 验证是否被修改,是否过期,是否已经退出 (点击退出,把token存入redis,加一个过期时间),任何一个问题,return 401没有权限操作,通过继续下一步操作
  • 安全问题及优化
    • 1.token加过期时间 retoken。
      • 登录成功后返回 token(3小时) retoken(4小时),当快到期的时候客户端携带retoken来换取新的token更新
    • 2.oa系统公司内部使用加ip地址过滤
    • 3.https证书加密

1.前端短信登录界面

在这里插入图片描述

src\components\Login.vue

  <!-- 1-短信登录 --><div class="inp" v-show="user.login_type==1"><input v-model="user.account" type="text" placeholder="手机号码" class="user"><input v-model="user.code"  type="text" class="code" placeholder="短信验证码"><el-button id="get_code" type="primary" @click="sendsms">获取验证码</el-button><div class="rember"><label><input type="checkbox" class="no" v-model="user.rememberMe"/><span>记住我</span></label><p>忘记密码</p></div><button class="login_btn" @click="loginmobile">登录</button><p class="go_login" >没有账号 <router-link to="/register">立即注册</router-link></p></div>
// 点击事件:发送短信验证码
const sendsms =()=>{//在前端正则验证手机号是否正确let reg= /^1[3-9]\d{9}$/if (!reg.test(user.account)){alert("[前端]手机号校验失败!")return false;}http.get(`/sendsms/?phone=${this.account}`).then((result) => {if (result.data.code == "200") {alert("发送成功!")} else {alert(result.data.message)}}).catch((err) => {alert(err)});
}
// 点击事件:登录按钮
const loginmobile =()=>{http.post("/login/",{"mobile":user.account,"code":user.code}).then(res => {if (res.data.code=="200") { //登录成功localStorage.setItem('userid',res.data.userid); //客户端存储useridlocalStorage.setItem('token',res.data.token); //客户端存储tokenreturn router.push("/"); //跳转主页} else {return router.push("/login"); //登录失败-->调整登录页面}}).catch((err) => {console.log(err);});
}

2.发送短信接口与短信登录接口

  这里使用容联云服务,来通过短信发送验证码

云通讯后台管理:https://console.yuntongxun.com/member/numbermanager
容联云短信开发手册:https://doc.yuntongxun.com/pe/5f029ae7a80948a1006e776e

参考容联云短信开发手册,构建发送短信的工具类,代码如下:

#tools/common.py
from ronglian_sms_sdk import SmsSDK
import json
accId = '容联云通讯分配的主账号ID'
accToken = '容联云通讯分配的主账号TOKEN'
appId = '容联云通讯分配的应用ID'# 发送短信
def send_message(mobile,sms_code):sdk = SmsSDK(accId, accToken, appId)tid = '1'mobile = mobiledatas = (sms_code, )resp = sdk.sendMessage(tid, mobile, datas)data = json.loads(resp) #json-->对象print(data)if data['statusCode'] == '000000':return Truereturn False

接口:发送短信(验证码)接口、登录接口

# user/views.py
# 发送验证码/获取验证码接口
class SendMobileCodeView(APIView):def get(self, request):# send_sms前端: /sendsms/?phone=${this.account}/phone = request.GET.get('phone')print(phone)#if not re.match(r"1[3-9]\d{9}$",phone):#    return Response({"message":"手机号验证失败!","code":"410"})flag = r.get_str("phone")if flag:return Response({"message":"一分钟只能发送一次验证码,请稍稍后发送!","code":"200"})sms_code = random.randint(1000,9999)r.delete_str("sms_code")r.setex_str("sms_code",60*5,sms_code) # times:验证码5分钟有效期send_message(phone, sms_code) # 发送短信(验证码)r.setex_str("phone",60,phone) #同一个手机号60s内只能发送一次验证码return Response({"message":"发送成功","code":"200"})# 手机短信登录接口
class LoginView(APIView):def post(self, request):myphone = request.data.get("mobile")mycode = request.data.get("code")sms_code = r.get_str("sms_code") #从redis中取出系统生成的验证码if mycode == sms_code: #与前端发送来的验证码对比user = UsersModel.objects.filter(phone=myphone).first()# 获取用户信息 生成 jwt tokentoken = mjwt.jwt_encode({"userid":user.id,"exp":int(time.time()) + 3600}) return Response({"code":200,"token":token,"userid":user.id})else:return Response({"code":4001,"message":"验证码错误!"})

3.Vue 设置interceptors拦截器

客户端把token存在 localStorage中,以后每次请求在头部携带token。vue interceptors拦截器,对每次请求前统一在头部添加token

src\http\index.js

import axios from "axios"
import settings from "../settings";
import router from "../router"const http = axios.create({// timeout: 2500,                          // 请求超时,有大文件上传需要关闭这个配置baseURL: settings.host,     // 设置api服务端的默认地址[如果基于服务端实现的跨域,这里可以填写api服务端的地址,如果基于nodejs客户端测试服务器实现的跨域,则这里不能填写api服务端地址]withCredentials: false,                    // 是否允许客户端ajax请求时携带cookie
})// 请求拦截器 +token
http.interceptors.request.use((config) => {console.log("http请求之前");//获取登录后localStorage存储的tokenlet token = localStorage.getItem('token') if (token) {config.headers.Authorization = token;}return config;
}, (error) => {console.log("http请求错误");return Promise.reject(error);
});// 响应拦截器
http.interceptors.response.use((response) => {return response;
}, (error) => {if (error.code === "ERR_NETWORK") {ElMessage.error("网络异常,无法请求服务端信息!");}if (error.response.status === 401) {ElMessage.error("未登录或登录超时!限制本次请求操作!请求登录后继续!");return router.push("/login");}return Promise.reject(error);
});export default http;

4. 服务端验证采用自定义中间件方式实现

自定义中间件,继承MiddiwareMinxin类重写process_request.方法中

  • ​定义白名单,在登录前需要操作的接口放到白名单中
    • a.如果不在白名单,获取token,验证
    • ​b.验证是否被修改,是否过期,是否已经退出 (点击退出,把token存入redis,加一个过期时间),任何一个问题,return 401没有权限操作,通过继续下一步操作
from django.http import JsonResponse
from django.utils.deprecation import MiddlewareMixin
from tools.myjwt import mjwt
from tools.myredis import r
import timeclass PermitionMiddleware(MiddlewareMixin):def process_request(self, request):# 1.定义白名单,在登录前需要操作的接口放到白名单中wlist = ['/register/', '/login/', '/sendsms/']# 获取当前的urlpath = request.path# 2.如果不在白名单,获取token,验证if path not in wlist:try:token = request.headers.get('Authorization')data = mjwt.jwt_decode(token)except:return JsonResponse({"code": 401, "mes": "token不存在或者被修改"})# data没问题 ↓exp = int(data['exp'])now = int(time.time())# 判断是否过期if now > exp:return JsonResponse({"code": 401, "mes": "token已经过期不能操作"})#是否退出,退出时存tokenvalue = r.get_str(token)if value:return JsonResponse({"code": 401, "mes": "用户已经退出,不能操作"})# ↑↑↑3.验证是否被修改,是否过期,是否已经退出 (点击退出,把token存入redis, 加一个过期时间),任何一个问题,return 401没有权限操作,通过继续下一步操作

不要忘记在主项目下的settings.py文件下配置写好的自定义中间件

MIDDLEWARE = ['corsheaders.middleware.CorsMiddleware','django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',# 'user.middleware.PermitionMiddleware', #自定义中间件
]

5. 操作流程及效果图如下:

1.输入手机号,点击发送验证码
在这里插入图片描述
2.手机接收验证码
在这里插入图片描述

3.输入验证码后,点击登录
在这里插入图片描述


三、通过第三方平台进行登录

三方登录,这里以钉钉为例

1.准备工作

钉钉开放平台:https://open.dingtalk.com/

    1. 进入钉钉开放平台,注册登录钉钉账号
    1. 注册应用,配置回调地址

具体操作流程如下:


1.登录开发者后台
在这里插入图片描述
2.创建应用
在这里插入图片描述
3.安全设置
在这里插入图片描述
4.凭证与基础信息
在这里插入图片描述
5.权限管理
在这里插入图片描述


2.前端钉钉登录界面

  <!-- 0-密码登录 --><div class="inp" v-if="user.login_type==0"><input v-model="user.account" type="text" placeholder="用户名 / 手机号码 / 邮箱" class="user"><input v-model="user.password" type="password" class="pwd" placeholder="密码"><div class="rember"><label><input type="checkbox" class="no" v-model="user.rememberMe"/><span>记住我</span></label><p>忘记密码</p></div><button class="login_btn" @click="show_captcha">登录</button><p class="go_login" >没有账号 <router-link to="/register">立即注册</router-link></p><p><a :href="ddurl">钉钉登录</a></p></div>
onMounted(()=>{http.get("dingtalkLogin/").then((result) => {ddurl.value = result.data.url;console.log(result.data);}).catch((err) => {alert(err)});
})

3.后端逻辑处理

三方登录表:

  • 字段:id、userid(外键)、方式(wb、qq、dd)、uid、token、retoken

处理流程:

  • 1.点击钉钉登录,调用钉钉三方登录接口DingTalkLogin,跳转到钉钉授权页面
  • 2.授权通过,登录成功,根据回调地址进行成功接口的回调
    • 获取code、调用授权接口、获取uid
    • 根据token获取手机号
    • 查询三方登录表
      • 不存在,在用户表中进行注册,同时更新三方登录表
    • 根据uid获取用户信息,生成token,跳转到前端页面
# 钉钉三方登录接口
class DingTalkLogin(APIView):def get(self, request):from urllib.parse import quoteparams = [f"redirect_uri={quote('http://127.0.0.1:8000/user/dingtalkCallback/')}","response_type=code","client_id=dingrcnkswwakld0y5jx","scope=openid","prompt=consent"]url = "https://login.dingtalk.com/oauth2/auth?" + ("&".join(params))return Response({"url": url})# 钉钉回调接口(钉钉登录接口 点击登录后调用)
class DingTalkCallback(APIView):def get(self, request):authCode = request.query_params.get('authCode')# 根据authCode获取用户accessTokendata = {"clientId": "钉钉开放平台-Client ID","clientSecret": "钉钉开放平台-Client Secret","code": authCode,"grantType": "authorization_code"}resp = requests.post('https://api.dingtalk.com/v1.0/oauth2/userAccessToken', json=data).json()accessToken = resp.get('accessToken')# 根据accessToken获取用户信息headers = {"x-acs-dingtalk-access-token": accessToken}resp = requests.get('https://api.dingtalk.com/v1.0/contact/users/me', headers=headers).json()name = resp.get('nick')uid = resp.get('openId')phone = resp.get('mobile')print(name)print(uid)print(phone)# ---# 登录,查询三方登录表,是否存在Sfuser = SfLoginModel.objects.filter(uid__exact=uid).first()print("三方登录表中--->")print(Sfuser)if Sfuser is None:# 注册用户表和三方登录表(先判断用户表是否已有用户信息)user = UsersModel.objects.filter(phone__exact=phone).first()print(user)if user is None:userinfo = {"phone":phone,"username":name, "password":"123"}userSer = UsersSerializer(data=userinfo)if userSer.is_valid():userSer.save()else:return Response({"code":10001,"message":userSer.errors})# 存在用户,写入三方登录表sfinfo = {"type":1,"uid":uid,"token":accessToken,"user":user.id}sfSer = SfLoginSerializer(data=sfinfo)if sfSer.is_valid():sfSer.save()else:return Response({"code":10001,"message":sfSer.errors})else:#三方登录表中存有信息,uid->获取用户信息,生成token# 根据uid获取用户信息,生成token,跳转到前端页面user = Sfuser.userSfuser.token = accessTokenSfuser.save()# 生成jwt token 并返回前端payload = {"userid":user.id, "username":user.username,"exp":int(time.time()) + 3600}token = mjwt.jwt_encode(payload)payload["exp"] = int(time.time()) + 3600retoken = mjwt.jwt_encode(payload)query = [f"userid={payload['userid']}",f"username={payload['username']}",f"token={token}",f"retoken={retoken}"]return HttpResponseRedirect('http://localhost:3000/?' + '&'.join(query))

4.操作流程及效果图如下:

1.登录界面点击钉钉登录:
在这里插入图片描述

2.跳转钉钉授权登录页面
在这里插入图片描述
在这里插入图片描述
3.点击登录后,通过钉钉配置的回调接口,跳转自己的平台首页
在这里插入图片描述


在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3245680.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Flychat:跨越距离的心灵桥梁

在当今这个数字化时代&#xff0c;人们的沟通方式变得越来越多样化&#xff0c;而移动设备的普及更是极大地推动了这一趋势。我们几乎可以随时随地与他人进行交流&#xff0c;分享生活的点滴。然而&#xff0c;在享受这些便捷的同时&#xff0c;我们也时常会遇到一些小困扰——…

Rust 使用 panic! 还是不用 panic!

使用 panic! 还是不用 panic! 那么&#xff0c;该如何决定何时应该 panic! 以及何时应该返回 Result 呢&#xff1f;如果代码 panic&#xff0c;就没有恢复的可能。你可以选择对任何错误场景都调用 panic!&#xff0c;不管是否有可能恢复&#xff0c;不过这样就是你代替调用者…

年化18.9%的创业板趋势策略,使用模块化策略模板重构(代码+数据)

原创文章第590篇&#xff0c;专注“AI量化投资、世界运行的规律、个人成长与财富自由"。 昨天咱们分享的文章&#xff1a;”以交易为生“&#xff0c;基础设施很重要。 传统backtrader写策略的步骤是如下&#xff1a; 1、定义因子&#xff0c;比如动量roc&#xff1a; …

基于LSTM及其变体的回归预测

1 所用模型 代码中用到了以下模型&#xff1a; 1. LSTM&#xff08;Long Short-Term Memory&#xff09;&#xff1a;长短时记忆网络&#xff0c;是一种特殊的RNN&#xff08;循环神经网络&#xff09;&#xff0c;能够解决传统RNN在处理长序列时出现的梯度消失或爆炸的问题。L…

华为OD算法题汇总

60、计算网络信号 题目 网络信号经过传递会逐层衰减&#xff0c;且遇到阻隔物无法直接穿透&#xff0c;在此情况下需要计算某个位置的网络信号值。注意:网络信号可以绕过阻隔物 array[m][n]&#xff0c;二维数组代表网格地图 array[i][j]0&#xff0c;代表i行j列是空旷位置 a…

基于STM32的智能晾衣设计

1.简介 本设计的目的是开发一种湿度传感智能衣物干燥杆系统&#xff0c;这是一个由单片机控制芯片控制的实时检测系统。该系统使用 DHT11温湿度传感器&#xff0c;检测大气的温度和湿度&#xff0c;然后处理信息&#xff0c;控制电机&#xff0c;完成衣物的收集和干燥工作。  …

相控阵雷达原理详解

相控阵&#xff0c;即相位控制阵列&#xff0c;通过控制阵列各个单元的馈电相位来改变波束指向。 相控阵雷达的原理可以清晰地归纳为以下几点&#xff1a; 1. 基本构成&#xff1a; - 相控阵雷达&#xff0c;即相位控制电子扫描阵列雷达&#xff08;Phased Array Radar, PAR&a…

脚本新手必看!一文掌握${}在Shell脚本中的神操作!

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 变量引用与默认值📝 字符串操作📝 数组与索引📝 参数扩展与模式匹配⚓️ 相关链接 ⚓️📖 介绍 📖 在编程的广阔世界里,隐藏着无数小巧而强大的工具,它们如同魔法般简化着复杂的操作。今天,我将…

抖音换地方IP会马上更新地址吗?解析抖音IP地址变化的真相

随着移动互联网的飞速发展&#xff0c;短视频平台如抖音已深入人心&#xff0c;成为大众生活中不可或缺的一部分。其中&#xff0c;IP地址作为用户在互联网世界的“身份证”&#xff0c;不仅关系到用户的隐私安全&#xff0c;也直接影响着平台内容推送的精准性。当我们跨越地域…

【Neural signal processing and analysis zero to hero】- 1

The basics of neural signal processing course from youtube: 传送地址 Possible preprocessing steps Signal artifacts (not) to worry about doing visual based artifact rejection so that means that before you start analyzing, you can identify those data epic…

Python数据结构之实现自定义栈与队列详解

概要 在计算机科学中,栈(Stack)和队列(Queue)是两种常见的数据结构。它们在算法和数据处理方面有着广泛的应用。本文将详细介绍如何在Python中实现自定义的栈与队列,并包含详细的示例代码,帮助深入理解这两种数据结构的工作原理和使用方法。 栈(Stack) 什么是栈 栈…

i5 13490F比13400F性能强多少?13490F和i5 13400F性能对比评测

英特尔再一次带来了13代全新的中国特供版的小黑盒&#xff0c;即酷睿i5-13490F和i7-13790F这两款型号&#xff0c;这两款CPU相当于i5 13400F和i7 13700F升级版&#xff0c;拥有更高的频率和三级缓存&#xff0c;以获得更好的游戏性能。我们知道&#xff0c;i5 13490F是用作替代…

LLM 应用开发平台特训

引言 随着人工智能技术的飞速发展&#xff0c;大型语言模型&#xff08;LLM&#xff09;如 GPT 系列已成为构建智能应用的重要基础。LLMOps&#xff08;Large Language Model Operations&#xff09;作为管理 LLM 支持的应用程序生命周期的工具和最佳实践&#xff0c;正逐渐受到…

【 香橙派 AIpro评测】烧系统运行部署LLMS大模型跑开源yolov5物体检测并体验Jupyter Lab AI 应用样例(新手入门)

文章目录 一、引言⭐1.1下载镜像烧系统⭐1.2开发板初始化系统配置远程登陆&#x1f496; 远程ssh&#x1f496;查看ubuntu桌面&#x1f496; 远程向日葵 二、部署LLMS大模型&yolov5物体检测⭐2.1 快速启动LLMS大模型&#x1f496;拉取代码&#x1f496;下载mode数据&#x…

C++树(二)【直径,中心】

目录&#xff1a; 树的直径&#xff1a; 树的直径的性质&#xff1a; 性质1&#xff1a;直径的端点一定是叶子节点 性质2&#xff1a;任意点的最长链端点一定是直径端点。 性质3&#xff1a;如果一棵树有多条直径,那么它们必然相交&#xff0c;且有极长连…

.NET MAUI开源架构_1.学习资源分享

最近需要开发Android的App&#xff0c;想预研下使用.NET开源架构.NET MAUI来开发App程序。因此网上搜索了下相关资料&#xff0c;现在把我查询的结果记录下&#xff0c;方便后面学习。 1.官方文档 1.1MAUI官方学习网站 .NET Multi-Platform App UI 文档 - .NET MAUI | Micro…

Python实战MySQL之数据库操作全流程详解

概要 MySQL是一种广泛使用的关系型数据库管理系统,Python可以通过多种方式与MySQL进行交互。本文将详细介绍如何使用Python操作MySQL数据库,包括安装必要的库、连接数据库、执行基本的CRUD(创建、读取、更新、删除)操作,并包含具体的示例代码,帮助全面掌握这一过程。 准…

CodeSouler:AI赋能,编程效率的革命性飞跃!

&#x1f525; 功能大揭秘&#xff0c;让你的代码飞起来&#xff01;&#x1f525; 01 添加代码注释 &#x1f4dd; 告别繁琐&#xff0c;一键添加精准注释&#xff01;提升代码清晰度&#xff0c;让后续维护不再是难题。 02 生成单元测试 &#x1f9ea; 智能分析&#xff0c;自…

C1W4.LAB.Vector manipulation+Hash functions and multiplanes

理论课&#xff1a;C1W4.Machine Translation and Document Search 文章目录 Python 中的矢量操作Transforming vectorsExample 1Example 2 Frobenius Norm Hash functions and multiplanesBasic Hash tablesPlanesHash Function with multiple planesRandom PlanesDocument v…

苹果x怎么录屏?手把手教你操作

随着社交媒体和视频平台的兴起&#xff0c;人们越来越习惯于通过视频来分享生活点滴、传播信息。苹果X手机凭借其出色的性能和高清屏幕&#xff0c;成为了许多用户录制屏幕视频的首选设备。可苹果x怎么录屏呢&#xff1f;本文将详细介绍苹果x手机的内置录屏方法&#xff0c;通过…