【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://www.mzph.cn/pingmian/47055.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

记录些MySQL题集(9)

MySQL之死锁问题分析、事务隔离与锁机制的底层原理剖析 一、MySQL中的死锁现象 所谓的并发事务&#xff0c;本质上就是MySQL内部多条工作线程并行执行的情况&#xff0c;也正由于MySQL是多线程应用&#xff0c;所以需要具备完善的锁机制来避免线程不安全问题的问题产生&#…

手机如何伪装ip网络地址

伪装IP地址是指通过技术手段修改网络设备的IP地址&#xff0c;使其看起来像是来自另一个网络位置。这种技术通常用于隐藏真实的网络活动&#xff0c;以保护隐私。那么&#xff0c;手机如何伪装IP网络地址&#xff1f; 要在手机上伪装IP地址&#xff0c;‌可以通过下载和安装手机…

Spring事件监听机制详解

Spring事件监听机制详解 在现代软件开发中&#xff0c;解耦和灵活性是两个非常重要的设计原则。Spring 框架通过事件驱动的编程模型&#xff0c;实现了组件之间的松耦合。本文将介绍Spring事件监听机制的原理&#xff0c;并通过示例展示如何实现这一机制。 什么是Spring事件监…

数据资产通证化,堪比20年前的房地产?

大数据产业创新服务媒体 ——聚焦数据 改变商业 想象一下&#xff0c;一个简单的点击&#xff0c;一次不经意的搜索&#xff0c;一段简短的对话&#xff0c;它们在数字世界里留下了什么&#xff1f;是的&#xff0c;是数据。这些看似微不足道的数字碎片&#xff0c;汇聚成海&a…

【python】PyQt5的窗口界面的各种交互逻辑实现,轻松掌控图形化界面程序

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

【中项】系统集成项目管理工程师-第一模块:IT技术和管理-1.1信息与信息化-1.1.2信息系统基础

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&#xff0c;目前涵盖了计算机软件、计算机网络、计算机应…

Dart语法问答到实践

语法问答 Dart语法输出调试信息的方法叫&#xff1f; print Dart语言里定义抽象类的关键字是&#xff1f; abstract Dart语言里String转Int的方法是&#xff1f; int.parse Dart语言的数据类型String是首字母大写&#xff0c;而int是首字母小写&#xff1f; 受c/c和java的影响&…

Office动态水印终于来了

在信息安全日益重要的今天&#xff0c;保护敏感信息变得尤为关键。目前&#xff0c;动态水印甚至是盲水印技术已经在各种企业软件中广泛应用&#xff0c;常见的钉钉和企业微信等都已经支持此类技术&#xff0c;用户查看消息时画面会显示对应用户的姓名和工号等&#xff0c;而作…

小程序-视图与逻辑

一、页面导航 声明式导航 编程式导航 导航传参 1.声明式导航传参 2.编程式导航传参 3.在onload中接收导航参数 二、页面事件 下拉刷新 上拉触底 三、生命周期 分类 生命周期函数分类 1.应用的生命周期函数 2.页面的生命周期函数 四、WXS脚本 基础语法 wxs的特点 五、案…

Matlab学习笔记01 - 基本数据类型

Matlab学习笔记01 - 基本数据类型 1、数据类型转换2、矩阵2.1 访问单个矩阵元素2.2 访问多个矩阵元素2.3 矩阵转置 3、字符与字符串4、数值与字符串5、元胞数组 1、数据类型转换 十进制转十六进制字符串‘FF’ >> hex2dec(3ff)ans 1023十进制转十六进制字符串 >>…

几何相关计算

目录 一、 判断两个矩形是否相交 二、判断两条线段是否相交 三、判断点是否在多边形内 四、垂足计算 五、贝塞尔曲线 六、坐标系 一、 判断两个矩形是否相交 当矩形1的最大值比矩形2的最小值都小&#xff0c;那矩形1和矩形2一定不相交&#xff0c;其他同理。 struct Po…

GaussDB数据库使用gs_loader导入数据

1、创建用户并授予使用权限 CREATE USER gsloader WTH PASSWORD Gsloader14; GRANT ALL ON FUNCTlON copy_error_log_create() TO gsloader; GRANT ALL ON SCHEMA public To gsloader; SELECT copy_error_log_create(); SELECT copy_summary_create(); GRANT ALL FRIVILEGES ON…

阐述软件23种设计模式背后的图论和代数结构基础

软件设计模式是一套被广泛认可的解决特定设计问题的解决方案,它们在软件开发中被重复使用。虽然设计模式本身并不直接依赖于图论或代数结构,但这些数学概念为理解和实现某些设计模式提供了理论基础。以下是一些设计模式以及它们可能与图论和代数结构相关的方面: 1. **策略模…

华为OD 机试真题 - 分割均衡字符串(Python)

题目描述 均衡串定义:字符串只包含两种字符&#xff0c;且两种字符的个数相同。 给定一个均衡字符串&#xff0c;请给出可分割成新的均衡子串的最大个数。 约定字符串中只包含大写的’X"和’Y’两种字符。 输入描述 均衡串:XXYYXY 字符串的长度[2,10000]。给定的字符…

keepalive简单配置

一、keepalive相关知识 1.1 keepalive介绍 keepalive即LVS集群当中的高可用架构&#xff0c;只是针对调度器的高可用。是高可用的HA架构。 keepalive就是基于VRRP协议来实现LVS高可用的方案。 组播地址 224.0.0.18&#xff0c;根据组播地址进行通信&#xff0c;主备之间发送…

10.1 标注、注记图层和注记整体说明

文章目录 前言标注、注记图层和注记QGis中的标注QGis中的注释(Annotation)图层QGis中的注记 总结 前言 介绍标注、注记图层和注记说明&#xff1a;文章中的示例代码均来自开源项目qgis_cpp_api_apps 标注、注记图层和注记 有时地图需要使用一些文字信息说明其中的地理要素或其…

OSX MongoDB 安装与配置指南

OSX MongoDB 安装与配置指南 MongoDB 是一款流行的开源 NoSQL 数据库,广泛用于数据存储、索引和实时分析。本指南将详细介绍在 macOS(OSX)操作系统上安装和配置 MongoDB 的步骤。 1. 安装 MongoDB 1.1 使用 Homebrew 安装 Homebrew 是 macOS 上的包管理器,可以简化软件…

如何落地实际场景,解决跨境传输共性需求?免费白皮书可下载

在全球化的背景下&#xff0c;海外市场对于数据驱动的产品和服务的需求不断增加&#xff0c;各行业数据跨境传输也日趋频繁&#xff0c;在这种前景下&#xff0c;越来越多的企业寻求更深度的跨国业务及合作&#xff0c;因此&#xff0c;企业数据跨境流动也成为了势不可挡的趋势…

51单片机嵌入式开发:11、 STC89C52RC 实现一个滑动的led点阵程序

STC89C52RC 实现一个滑动的led点阵程序 1 概述2 LED点阵介绍2.1 LED概述2.2 LED点阵注意事项 3 LED点阵原理3.1 Led点阵内部电路3.2 原理图电路 4 软件实现点阵图案的滑动4.1 软件工程代码4.2 Protues仿真 5 扩展74HC595&#xff08;后续专题开展&#xff09;6 总结 第十一节 1…

如何制定高效的媒体公关解决方案

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体公关解决方案是指企业或组织为提升品牌形象、塑造公众认知、应对危机事件等目的&#xff0c;通过媒体渠道制定并实施的一系列公关策略和行动计划。这一解决方案旨在通过有效的媒体沟…