鉴权 前后端常见的几种鉴权方式

2023-05-16

https://juejin.cn/post/6844903927100473357

鉴权(authentication)是指验证用户是否拥有访问系统的权利。传统的鉴权是通过密码来验证的。这种方式的前提是,每个获得密码的用户都已经被授权。在建立用户时,就为此用户分配一个密码,用户的密码可以由管理员指定,也可以由用户自行申请。这种方式的弱点十分明显:一旦密码被偷或用户遗失密码,情况就会十分麻烦,需要管理员对用户密码进行重新修改,而修改密码之前还要人工验证用户的合法身份。
为了克服这种鉴权方式的缺点,需要一个更加可靠的鉴权方式。主流鉴权方式是利用认证授权来验证数字签名的正确与否。
逻辑上,授权发生在鉴权之后,而实际上,这两者常常是一个过程。

鉴权包括两个方面:
用户鉴权,网络对用户进行鉴权,防止非法用户占用网络资源。
网络鉴权,用户对网络进行鉴权,防止用户接入了非法的网络,被骗取关键信息。
这种双向的认证机制,就是AKA(Authentication and Key Agreement,鉴权和密钥协商)鉴权。

一、四种鉴权方式
目前我们常用的鉴权有四种:

HTTP Basic Authentication
session-cookie
Token 验证
OAuth(开放授权)

二、HTTP Basic Authentication
这种授权方式是浏览器遵守http协议实现的基本授权方式,HTTP协议进行通信的过程中,HTTP协议定义了基本认证允许HTTP服务器对客户端进行用户身份证的方法。
认证过程:

1、 客户端向服务器请求数据,请求的内容可能是一个网页或者是一个ajax异步请求,此时,假设客户端尚未被验证,则客户端提供如下请求至服务器:
Get /index.html HTTP/1.0
Host:www.google.com
复制代码2、 服务器向客户端发送验证请求代码401,(WWW-Authenticate: Basic realm=”google.com”这句话是关键,如果没有客户端不会弹出用户名和密码输入界面)服务器返回的数据大抵如下:
HTTP/1.0 401 Unauthorised
Server: SokEvo/1.0
WWW-Authenticate: Basic realm=”google.com”
Content-Type: text/html
Content-Length: xxx
复制代码3、 当符合http1.0或1.1规范的客户端(如IE,FIREFOX)收到401返回值时,将自动弹出一个登录窗口,要求用户输入用户名和密码。
4、 用户输入用户名和密码后,将用户名及密码以BASE64加密方式加密,并将密文放入前一条请求信息中,则客户端发送的第一条请求信息则变成如下内容:
Get /index.html HTTP/1.0
Host:www.google.com
Authorization: Basic d2FuZzp3YW5n
复制代码注:d2FuZzp3YW5n表示加密后的用户名及密码(用户名:密码 然后通过base64加密,加密过程是浏览器默认的行为,不需要我们人为加密,我们只需要输入用户名密码即可)
5、 服务器收到上述请求信息后,将 Authorization 字段后的用户信息取出、解密,将解密后的用户名及密码与用户数据库进行比较验证,如用户名及密码正确,服务器则根据请求,将所请求资源发送给客户端
效果:
客户端未未认证的时候,会弹出用户名密码输入框,这个时候请求时属于 pending 状态,当用户输入用户名密码的时候客户端会再次发送带 Authentication 头的请求。

认证成功:

server.js
let express = require(“express”);
let app = express();

app.use(express.static(__dirname+’/public’));

app.get("/Authentication_base",function(req,res){
console.log(‘req.headers.authorization:’,req.headers)
if(!req.headers.authorization){
res.set({
‘WWW-Authenticate’:‘Basic realm=“wang”’
});
res.status(401).end();
}else{
let base64 = req.headers.authorization.split(" “)[1];
let userPass = new Buffer(base64, ‘base64’).toString().split(”😊;
let user = userPass[0];
let pass = userPass[1];
if(user==“wang”&&pass=“wang”){
res.end(“OK”);
}else{
res.status(401).end();
}

}

})

app.listen(9090)
复制代码index.html

HTTP Basic Authentication 复制代码优点:   基本认证的一个优点是基本上所有流行的网页浏览器都支持基本认证。基本认证很少在可公开访问的互联网网站上使用,有时候会在小的私有系统中使用(如路由器网页管理接口)。后来的机制HTTP摘要认证是为替代基本认证而开发的,允许密钥以相对安全的方式在不安全的通道上传输。   程序员和系统管理员有时会在可信网络环境中使用基本认证,使用Telnet或其他明文网络协议工具手动地测试Web服务器。这是一个麻烦的过程,但是网络上传输的内容是人可读的,以便进行诊断。 缺点:   虽然基本认证非常容易实现,但该方案创建在以下的假设的基础上,即:客户端和服务器主机之间的连接是安全可信的。特别是,如果没有使用SSL/TLS这样的传输层安全的协议,那么以明文传输的密钥和口令很容易被拦截。该方案也同样没有对服务器返回的信息提供保护。   现存的浏览器保存认证信息直到标签页或浏览器被关闭,或者用户清除历史记录。HTTP没有为服务器提供一种方法指示客户端丢弃这些被缓存的密钥。这意味着服务器端在用户不关闭浏览器的情况下,并没有一种有效的方法来让用户注销。 三、session-cookie 3.1 cookie Http协议是一个无状态的协议,服务器不会知道到底是哪一台浏览器访问了它,因此需要一个标识用来让服务器区分不同的浏览器。cookie 就是这个管理服务器与客户端之间状态的标识。 cookie 的原理是,浏览器第一次向服务器发送请求时,服务器在 response 头部设置 Set-Cookie 字段,浏览器收到响应就会设置 cookie 并存储,在下一次该浏览器向服务器发送请求时,就会在 request 头部自动带上 Cookie 字段,服务器端收到该 cookie 用以区分不同的浏览器。当然,这个 cookie 与某个用户的对应关系应该在第一次访问时就存在服务器端,这时就需要 session 了。 const http = require('http') http.createServer((req, res) => { if (req.url === '/favicon.ico') { return } else { res.setHeader('Set-Cookie', 'name=zhunny') res.end('Hello Cookie') } }).listen(3000) 复制代码3.2 session session 是会话的意思,浏览器第一次访问服务端,服务端就会创建一次会话,在会话中保存标识该浏览器的信息。它与 cookie 的区别就是 session 是缓存在服务端的,cookie 则是缓存在客户端,他们都由服务端生成,为了弥补 Http 协议无状态的缺陷。 3.3 session-cookie认证

服务器在接受客户端首次访问时在服务器端创建seesion,然后保存seesion(我们可以将seesion保存在 内存中,也可以保存在redis中,推荐使用后者),然后给这个session生成一个唯一的标识字符串,然后在 响应头中种下这个唯一标识字符串。
签名。这一步通过秘钥对sid进行签名处理,避免客户端修改sid。(非必需步骤)
浏览器中收到请求响应的时候会解析响应头,然后将sid保存在本地cookie中,浏览器在下次http请求的请求头中会带上该域名下的cookie信息。
服务器在接受客户端请求时会去解析请求头cookie中的sid,然后根据这个sid去找服务器端保存的该客户端的session,然后判断该请求是否合法。

const http = require(‘http’)
//此时session存在内存中
const session = {}
http.createServer((req, res) => {
const sessionKey = ‘sid’
if (req.url === ‘/favicon.ico’) {
return
} else {
const cookie = req.headers.cookie
//再次访问,对sid请求进行认证
if (cookie && cookie.indexOf(sessionKey) > -1) {
res.end(‘Come Back’)
}
//首次访问,生成sid,保存在服务器端
else {
const sid = (Math.random() * 9999999).toFixed()
res.setHeader(‘Set-Cookie’, ${sessionKey}=${sid})
session[sid] = { name: ‘zhunny’ }
res.end(‘Hello Cookie’)
}
}
}).listen(3000)
复制代码3.4 redis
redis是一个键值服务器,可以专门放session的键值对。如何在koa中使用session:
const koa = require(‘koa’)
const app = new koa()
const session = require(‘koa-session’)

const redisStore = require(‘koa-redis’)
const redis = require(‘redis’)
const redisClient = redis.createClient(6379, ‘localhost’)

const wrapper = require(‘co-redis’)
const client = wrapper(redisClient)

//加密sessionid
app.keys = [‘session secret’]

const SESS_CONFIG = {
key: ‘kbb:sess’,
//此时让session存储在redis中
store: redisStore({ client })
}

app.use(session(SESS_CONFIG, app))

app.use(ctx => {
//查看redis中的内容
redisClient.keys(’*’, (errr, keys) => {
console.log(‘keys:’, keys)
keys.forEach(key => {
redisClient.get(key, (err, val) => {
console.log(val)
})
})
})
if (ctx.path === ‘/favicon.ico’) return
let n = ctx.session.count || 0
ctx.session.count = ++n
ctx.body = 第${n}次访问
})

app.listen(3000)
复制代码3.5 用户登录认证
使用session-cookie做登录认证时,登录时存储session,退出登录时删除session,而其他的需要登录后才能操作的接口需要提前验证是否存在session,存在才能跳转页面,不存在则回到登录页面。
在koa中做一个验证的中间件,在需要验证的接口中使用该中间件。
//前端代码
async login() {
await axios.post(’/login’, {
username: this.username,
password: this.password
})
},
async logout() {
await axios.post(’/logout’)
},
async getUser() {
await axios.get(’/getUser’)
}
复制代码//中间件 auth.js
module.exports = async (ctx, next) => {
if (!ctx.session.userinfo) {
ctx.body = {
ok: 0,
message: “用户未登录” };
} else {
await next();
} };
//需要验证的接口
router.get(’/getUser’, require(‘auth’), async (ctx) => {
ctx.body = {
message: “获取数据成功”,
userinfo: ctx.session.userinfo
}
})
//登录
router.post(’/login’, async (ctx) => {
const {
body
} = ctx.request
console.log(‘body’, body)
//设置session
ctx.session.userinfo = body.username;
ctx.body = {
message: “登录成功”
}
})
//登出
router.post(’/logout’, async (ctx) => {
//设置session
delete ctx.session.userinfo
ctx.body = {
message: “登出系统”
}
})
复制代码四、Token
token 是一个令牌,浏览器第一次访问服务端时会签发一张令牌,之后浏览器每次携带这张令牌访问服务端就会认证该令牌是否有效,只要服务端可以解密该令牌,就说明请求是合法的,令牌中包含的用户信息还可以区分不同身份的用户。一般 token 由用户信息、时间戳和由 hash 算法加密的签名构成。
4.1 Token认证流程

客户端使用用户名跟密码请求登录
服务端收到请求,去验证用户名与密码
验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者Local Storage 里
客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
服务端收到请求,然后去验证客户端请求里面带着的 Token(request头部添加Authorization),如果验证成功,就向客户端返回请求的数据 ,如果不成功返回401错误码,鉴权失败。

4.2 Token和session的区别
session-cookie的缺点:
(1)认证方式局限于在浏览器中使用,cookie 是浏览器端的机制,如果在app端就无法使用 cookie。
(2)为了满足全局一致性,我们最好把 session 存储在 redis 中做持久化,而在分布式环境下,我们可能需要在每个服务器上都备份,占用了大量的存储空间。
(3)在不是 Https 协议下使用 cookie ,容易受到 CSRF 跨站点请求伪造攻击。
token的缺点:
(1)加密解密消耗使得 token 认证比 session-cookie 更消耗性能。
(2)token 比 sessionId 大,更占带宽。
两者对比,它们的区别显而易见:
(1)token 认证不局限于 cookie ,这样就使得这种认证方式可以支持多种客户端,而不仅是浏览器。且不受同源策略的影响。
(2)不使用 cookie 就可以规避CSRF攻击。
(3)token 不需要存储,token 中已包含了用户信息,服务器端变成无状态,服务器端只需要根据定义的规则校验这个 token 是否合法就行。这也使得 token 的可扩展性更强。
4.3 JWT(JSON Web Token)
基于 token 的解决方案有许多,常用的是JWT,JWT 的原理是,服务器认证以后,生成一个 JSON 对象,这个 JSON 对象肯定不能裸传给用户,那谁都可以篡改这个对象发送请求。因此这个 JSON 对象会被服务器端签名加密后返回给用户,返回的内容就是一张令牌,以后用户每次访问服务器端就带着这张令牌。
这个 JSON 对象可能包含的内容就是用户的信息,用户的身份以及令牌的过期时间。
4.3.1 JWT的组成部分
在该网站JWT,可以解码或编码一个JWT。一个JWT形如:

它由三部分组成:Header(头部)、Payload(负载)、Signature(签名)。

Header部分是一个JSON对象,描述JWT的元数据。一般描述信息为该Token的加密算法以及Token的类型。{“alg”: “HS256”,“typ”: “JWT”}的意思就是,该token使用HS256加密,token类型是JWT。这个部分基本相当于明文,它将这个JSON对象做了一个Base64转码,变成一个字符串。Base64编码解码是有算法的,解码过程是可逆的。头部信息默认携带着两个字段。
Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。有7个官方字段,还可以在这个部分定义私有字段。一般存放用户名、用户身份以及一些JWT的描述字段。它也只是做了一个Base64编码,因此肯定不能在其中存放秘密信息,比如说登录密码之类的。
Signature是对前面两个部分的签名,防止数据篡改,如果前面两段信息被人修改了发送给服务器端,此时服务器端是可利用签名来验证信息的正确性的。签名需要密钥,密钥是服务器端保存的,用户不知道。算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。

4.3.2 JWT的特点

JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
JWT 不加密的情况下,不能将秘密数据写入 JWT。
JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。

4.3.3 JWT验证用户登录
//前端代码
//axios的请求拦截器,在每个request请求头上加JWT认证信息
axios.interceptors.request.use(
config => {
const token = window.localStorage.getItem(“token”);
if (token) {
// 判断是否存在token,如果存在的话,则每个http header都加上token
// Bearer是JWT的认证头部信息
config.headers.common[“Authorization”] = “Bearer " + token;
}
return config;
},
err => {
return Promise.reject(err);
}
);
//登录方法:在将后端返回的JWT存入localStorage
async login() {
const res = await axios.post(”/login-token", {
username: this.username,
password: this.password
});
localStorage.setItem(“token”, res.data.token);
},
//登出方法:删除JWT
async logout() {
localStorage.removeItem(“token”);
},
async getUser() {
await axios.get("/getUser-token");
}
复制代码//后端代码
const jwt = require(“jsonwebtoken”);
const jwtAuth = require(“koa-jwt”);
//用来签名的密钥
const secret = “it’s a secret”;

router.post("/login-token", async ctx => {
const { body } = ctx.request;
//登录逻辑,略,即查找数据库,若该用户和密码合法,即将其信息生成一个JWT令牌传给用户
const userinfo = body.username;
ctx.body = {
message: “登录成功”,
user: userinfo,
// 生成 token 返回给客户端
token: jwt.sign(
{
data: userinfo,
// 设置 token 过期时间,一小时后,秒为单位
exp: Math.floor(Date.now() / 1000) + 60 * 60
},
secret
)
};
});

//jwtAuth这个中间件会拿着密钥解析JWT是否合法。
//并且把JWT中的payload的信息解析后放到state中,ctx.state用于中间件的传值。
router.get(
“/getUser-token”,
jwtAuth({
secret
}),
async ctx => {
// 验证通过,state.user
console.log(ctx.state.user);
ctx.body = {
message: “获取数据成功”,
userinfo: ctx.state.user.data
};
}
)
//这种密码学的方式使得token不需要存储,只要服务端能拿着密钥解析出用户信息,就说明该用户是合法的。
//若要更进一步的权限验证,需要判断解析出的用户身份是管理员还是普通用户。
复制代码五、OAuth(开放授权)
OAuth(Open Authorization)是一个开放标准,允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方网站或分享他们数据的所有内容,为了保护用户数据的安全和隐私,第三方网站访问用户数据前都需要显式的向用户征求授权。我们常见的提供OAuth认证服务的厂商有支付宝,QQ,微信。
OAuth协议又有1.0和2.0两个版本。相比较1.0版,2.0版整个授权验证流程更简单更安全,也是目前最主要的用户身份验证和授权方式。
关于OAuth相关文章,可以查看 OAuth 2.0 的一个简单解释、理解OAuth 2.0、OAuth 2.0 的四种方式
5.1 OAuth认证流程
OAuth就是一种授权机制。数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据。系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使用。
OAuth有四种获取令牌的方式,不管哪一种授权方式,第三方应用申请令牌之前,都必须先到系统备案,说明自己的身份,然后会拿到两个身份识别码:客户端 ID(client ID)和客户端密钥(client secret)。这是为了防止令牌被滥用,没有备案过的第三方应用,是不会拿到令牌的。
在前后端分离的情境下,我们常使用授权码方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌。
5.2 GitHub第三方登录示例
我们用例子来理清授权码方式的流程。

在GitHub中备案第三方应用,拿到属于它的客户端ID和客户端密钥。

在github-settings-developer settings中创建一个OAuth App。并填写相关内容。填写完成后Github会给你一个客户端ID和客户端密钥。

此时在你的第三方网站就可以提供一个Github登录链接,用户点击该链接后会跳转到Github。这一步拿着客户端ID向Github请求授权码code。

const config = {
client_id: ‘28926186082164bbea8f’,
client_secret: ‘07c4fdae1d5ca458dae3345b6d77a0add5a785ca’
}

router.get(’/github/login’, async (ctx) => {
var dataStr = (new Date()).valueOf();
//重定向到认证接口,并配置参数
var path = “https://github.com/login/oauth/authorize”;
path += ‘?client_id=’ + config.client_id;

//转发到授权服务器
ctx.redirect(path);
})
复制代码
用户跳转到Github,输入Github的用户名密码,表示用户同意使用Github身份登录第三方网站。此时就会带着授权码code跳回第三方网站。跳回的地址在创建该OAuth时已经设置好了。http://localhost:3000/github/callback
第三方网站收到授权码,就可以拿着授权码、客户端ID和客户端密钥去向Github请求access_token令牌。
Github收到请求,向第三方网站颁发令牌。
第三方网站收到令牌,就可以暂时拥有Github一些请求的权限,比如说拿到用户信息,拿到这个用户信息之后就可以构建自己第三方网站的token,做相关的鉴权操作。

router.get(’/github/callback’, async (ctx) => {
console.log(‘callback…’)
const code = ctx.query.code;
const params = {
client_id: config.client_id,
client_secret: config.client_secret,
code: code
}
let res = await axios.post(‘https://github.com/login/oauth/access_token’, params)
const access_token = querystring.parse(res.data).access_token
res = await axios.get(‘https://api.github.com/user?access_token=’ + access_token)
console.log(‘userAccess:’, res.data)
ctx.body = <h1>Hello ${res.data.login}</h1> <img src="${res.data.avatar_url}" alt=""/>

})
复制代码OAuth授权的登陆流程图:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

鉴权 前后端常见的几种鉴权方式 的相关文章

  • L298电机驱动模块STM32程序封装

    L298电机驱动模块STM32程序封装 程序可以控制电机驱动模块实现 前进 后退 左右转 停止 PWM速度调节 适用于多种电机奁动模块 1 适用模块 xff1a L298N电机驱动模块 TB6612F电机驱动模块 L293D电机驱动模块 2
  • C#,生成字符串整数校验码(Checksum)的谷歌(Google)算法与源代码

    如题 校验码系统是产生校验码并校验包括校验码在内的字符串的一套规则 它可以防止在抄录和键入字符串时产生的错误 一般生成 MD5 校验 xff0c 也可以生成 进行简单 快速的 整数 校验 谷歌开源 xff0c 很实用的整数校验码生成代码 u
  • AD常用快捷键(自用)

    走线角度切换 xff1a shift 43 空格 走线线宽切换 xff1a shift 43 W 快速查找元件 xff1a J 43 C 快速对齐 xff1a a 查看相同网络连接 xff1a Alt 43 单击网络 切换单层显示和多层显示
  • stm32软件仿真调试

    下面是一个单片机STM32RCT6的PA8 xff0c PA9 xff0c PA10引脚输出PWM波形的仿真步骤 xff0c 此外还展示了软件运行过程 xff0c 如何查看全局变量的实时数据 每一步我都做了截图 xff0c 大家照着一步步来
  • 电容种类特性

  • STM32F103 PB3,PB4,PA15,IO不可控问题

    STM32默认启动时PB4 PB3 PA15三个引脚不是普通IO xff0c 而是JTAG的复用功能 xff0c 分别为JNTRST JTDI JTDO 由上可以知要使PB3可以用 须关闭JTAG DP SW DP 可以不管 添加以下配置即
  • STM32CubeMX | STM32使用HAL库串口收发

    一 串口实现printf 1 hal配置 2 重定向代码 span class token comment USER CODE BEGIN Includes span span class token macro property span
  • 继电器开关阿里云IOT上云设置操作

    阿里云IOT继电器开关产品 阿里云IOT设备接入的入口有两个 一是物联网平台 xff0c 二是生活物联网平台 飞燕平台 xff09 飞燕平台主要是为生成APP用 xff0c 它创建的产品也会出现在物联网平台下 物联网平台下创建更方便配置相对
  • STM32定时器使用计算

    STM32F103ZE有8个定时器 xff0c 其中2个高级定时器 TIM1 TIM8 xff08 带死区控制 xff09 xff0c 4个通用定时器 xff08 TIM2 TIM3 TIM4 TIM5 xff09 xff0c 2个基本定时
  • lwip select函数分析和优化

    我的设备有两个网卡 xff0c 我需要开两路socket xff0c 一路UDP xff0c 一路TCP xff0c lwip的版本是1 4 1的 xff0c 实际运行发现 xff0c UDP 运行一段时间以后挂了 xff0c 通信挂了 x
  • curl并发 c++

    QQ技术交流群 xff1a 386476712
  • ROS组网

    参考ROS实战之ROS组网的搭建 ROS ROS命令 xff08 三 xff09 ROS 信息命令 其实整个过程比想象中简单的多 首先保证所有运行 ROS 的机器 xff08 no matter it is a raspberry or a
  • Ubuntu16.04下完美切换Python版本

    转载自http blog csdn net u013894834 article details 75305752 Ubuntu16 04下完美切换Python版本 xff08 亲测 xff09 对于ubuntu 16 04 xff0c 由
  • ArduPilot-sitl中的一些操作记录

    ArduPilot 这么优秀的代码 提供了一套很方便的SITL仿真开发模式 在git clone代码的时候 已经将相关的东西下载下来了 问题是如何进行使用 首先要安装mavproxy 这个软件 pymavlink mavlink封装的pyt
  • 烧写自定义ArduPilot到自定义的开发板

    写在前面的话 xff1a 本篇章内容参看 怒飞垂云 的资料 将APM固件移植到自制硬件 实际操作过程中 xff0c 需要如下几个步骤 xff1a 先在ardupilot中的 waf distclean 完成清理 xff0c 主要删除了bui
  • 跨域资源共享CORS的那些事(二)

    跨域资源共享CORS的那些事 xff08 二 xff09 最近在为高性能开源API网关apisix写跨域插件 xff0c 发现该功能对协议要求要比较熟悉 xff0c 借此机会重新复习下跨域协议 xff0c 以及简要写下跨域功能的设计 文章目
  • 宅家学习,如何进行Kubernetes Ingress控制器的技术选型?

    导语 xff1a 在Kubernetes的实践 部署中 xff0c 为了解决 Pod 迁移 Node Pod 端口 域名动态分配等问题 xff0c 需要开发人员选择合适的 Ingress 解决方案 面对市场上众多Ingress产品 xff0
  • Linux下connect()函数的错误代码对应含义

    Linux下connect 函数的错误代码对应含义 windows和linux下的connect系统接口有自己的一套返回码以及返回含义 Linux EBADF xff1a 参数socket未指定一个合法的描述符ENOTSOCK 参数sock
  • git设置用户名密码

    git设置用户名密码 设置git用户名 xff0f 邮箱 span class hljs comment git span span class hljs comment config span span class hljs litera
  • 'python' 不是内部或外部命令,也不是可运行的程序或批处理文件。

    python 不是内部或外部命令 xff0c 也不是可运行的程序或批处理文件 我将python安装在D盘之后 xff0c 输入python xff0c 显示如下问题 span class hljs keyword D span gt pyt

随机推荐

  • git pull时遇到error: cannot lock ref 'xxx': ref xxx is at (一个commitID) but expected的解决办法

    git pull时遇到error cannot lock ref xxx ref xxx is at xff08 一个commitID xff09 but expected的解决办法 在执行git pull时遇到如下错误 xff1a spa
  • tar.gz和tar.bz2解压命令

    tar gz和tar bz2解压命令 网络上下载到linux源码包主要是tar gz和tar bz2压缩格式的 xff0c 有一部分是zip 解压tar gz命令是 tar zxvf xx tar gz 解压tar bz2的命令是 tar
  • 使用VS CODE+PlantUML高效画图

    使用VS CODE 43 PlantUML高效画图 自从发现了plantuml写脚本画图的方式之后 xff0c 爱上了画图 环境 xff1a MAC 前言 本文多数内容引用自官网文档和其他人的教程 xff0c 并非本人原创 xff0c 也谈
  • CMake多工程最小实现

    背景 xff1a 最近团队的新项目开始基于CMake作为工程管理 xff0c 结合VSCode作为IDE进行开发 xff0c 一个原因当然是为了可支持跨平台 原来我们的开发环境是使用VS系列IDE进行开发 xff0c 在底层框架完全改为CM
  • c++ aggregate 'std::stringstream ss' has incomplete type and cannot be defined

    c 43 43 aggregate std stringstream ss has incomplete type and cannot be defined 这个问题是使用了stringstream这个类 xff0c 但没有包含头文件ss
  • 阿里巴巴的“达摩院”,必是一场闹剧

    阿里巴巴的 达摩院 xff0c 必是一场闹剧 今天上午 xff0c 阿里巴巴成立 达摩院 xff0c 引入顶尖科学家3年研发投入将超千亿 的文章在网上刷屏了 在我看来 xff0c 马云在挑战科技规律 xff0c 这必是一场闹剧 前几年 xf
  • 一种解耦非线性优化的高效VI-SLAM系统-Snake-SLAM

    摘要 Snake SLAM 是一种可在低功率航空设备上稳定运行的VI SLAM 自主导航系统 跟踪前端具有地图复用 闭环 重定位功能 xff0c 并支持单目 立体和 RGBD 输入 该系统通过图论算法来减少关键帧并提出一种 延时地图 的方法
  • 关于视觉三维重建colmap 一期课程,我想说点什么

    为什么开colmap这门课 2019年硕士毕业进入驭势科技从事高精度地图算法职位 xff0c 闲暇时间便开启自己在B站上分享技术的历程 xff0c 如下早期视频 xff1a 但是发完这几次视频后 xff0c 发现每次录制的时候总会遗漏自己想
  • 关于视觉重定位(VPS)的工作经验分享

    在AR领域也呆了不短时间了 xff0c 也一直在做视觉定位相关的工作 xff0c 这里分享一下有意思的工作方向 xff0c 感兴趣的可以讨论或者联系我即可 首先简单区分AR和VR的区别 xff0c VR 属于虚拟现实 xff0c 即是由实入
  • python调用百度地图API 实现单点沿线轨迹运动

    百度地图API 可以做很多好玩的事情 xff0c 自己闲来无事 xff0c 先是照着一些资料做了热力图 xff0c 然后借助pyqt5做了一个简单的界面 xff0c 实现gps单点沿线 xff08 行车 xff09 的轨迹 先上程序界面和效
  • python 在测绘作业中的一些小应用(与cad交互)-1

    虽然笔者已经基本上告别了本科的测绘工程专业 xff0c 但是笔者的本科同学他们在实际作业中难免会遇到一些批量化 重复性劳动问题 xff0c 如果会编程 xff0c 写上一个小脚本 xff0c 无疑会提高工作效率 下面是笔者本科同学处理测量数
  • 阴影检测(shadow detect)

    不管是无人机影像或者其它方式摄取的图像 xff0c 由于光照 xff0c 难免会存在阴影 xff0c 笔者这篇文章介绍检测阴影一种简单的方式 参考论文 xff1a 1 Damaged Building Detection in Aerial
  • Scipy 和opencv 计算凸包(convexHull)

    凸包 xff1a 在数学中 xff0c 在实向量空间 V 中的一组点 X 的凸包或凸包络是包含 X 的最小凸集 来自 Wikipedia 通俗的来说就是包围一组散点的最小凸边形 在 scipy spatial 和 opencv 分别有计算凸
  • python 两个小技巧将字典写入txt或者json 文件

    1 不用 json 包 先来看一个 Python 的奇淫技巧 i 61 100 s1 61 str i 这样输出的不会是 100 xff0c 毫不疑问 但是 s1 61 43 str i 43 这样输出的结果 61 str i 于是看这一条
  • 时间序列预测——ARIMA模型

    文章链接 xff1a 时间序列预测 Prophet模型 https blog csdn net beiye article details 123353123 spm 61 1001 2014 3001 5502 SPSS软件实操 ARIM
  • 基本矩阵F和本质矩阵E的详细推导

    基本矩阵F E在计算机视觉中是提纯匹配点 恢复相机位姿的一个法宝 但是它是如何得到的 下面笔者做其简单的推导 如图下图 xff0c 两视几何图 其中C和C 分别代表左 右摄影中心 xff0c x和x 代表同名像点 xff0c e和e 代表极
  • [ubuntu]安装并使用python 3.6及与2.7的切换

    当前使用ubuntu14 04 1 添加python3 6安装包 xff0c 并安装 xff08 也可以去官网下载安装包 xff09 linux 报错E Unable To Locate Package Software propertie
  • Python + Requests 模拟登陆(含验证码)

    其实模拟登陆非常简单 xff0c 只要在打开网站的同时提交数据就可以了 下面通过登陆超星网来举例说明如何一步步实现模拟登陆 1 获取需要提交的数据 使用chrome的Network或者fiddler可以很轻易的得到我们想要的数据 xff0c
  • Cmake实现递归cpp和h

    为解决获取编译链所有C 43 43 源文件和头文件 Cmake实现递归目录 编程心得 拾随小笺
  • 鉴权 前后端常见的几种鉴权方式

    https juejin cn post 6844903927100473357 鉴权 xff08 authentication xff09 是指验证用户是否拥有访问系统的权利 传统的鉴权是通过密码来验证的 这种方式的前提是 xff0c 每