常见的鉴权方式简述

article/2025/9/19 7:49:37

一、什么是鉴权,为什么要鉴权

鉴权:是指验证用户是否有访问系统的权利。
为什么要鉴权 :对用户进行鉴权,防止非法用户占用网络资源,非法用户接入网络,被骗取关键信息

二、鉴权方式

Basic Auth

basic auth是一种用来允许网页浏览器或其他客户端程序在请求时提供用户名和口令形式的身份凭证的一种登录验证方式。

优点:
1、使用简单。
2、开发和调试工作简单。
缺点:
1、安全性低,如果没有使用SSL/TLS这样的传输层安全的协议,用户名和密码很大程度上存在被监听盗取的可能。
2、同时应用本地还需要保存用户名和密码,在应用本身的安全性来说,也存在很大问题;

使用:
1、在使用浏览器访问设置了 HTTP Basic Auth 的服务器时,会弹出对话框,输入用户名和密码即可。
2、客户端有可能也不需要用户交互,在第一次请求中就发送认证消息头,请求头格式如Authorization: Basic base64encode(username+“:”+password)

注:Response 中的 WWW-Authenticate 字段会指示浏览器弹出询问用户名和密码的提示框。

使用场景:
1、企业内部服务,
2、在小的私有系统中使用(如路由器网页管理接口)。

cookie

概念
存储在客户端(浏览器)本地的小型文本文件,用于辨别用户身份,保持浏览器会话。

  • cookie一般小于4kb
  • cookie是以key-value 格式存储的
  • expires属性
    • 会话型(默认) 存储在浏览器内存中,浏览器画面关闭自动删除
    • 持久型,存储在本地文件中,到期后或者浏览器强制删除后失效
  • path属性:定义站点上可以访问到该cookie的目录
  • domain属性:设置cookie所属的域
  • secure属性:指定是否使用https协议
  • httponly属性:用于防止客户端脚本通过document.cookie属性访问Cookie,有助于保护Cookie不被跨站脚本攻击窃取或篡改

使用flask设置cookie

cookie是服务器设置的,通过HTTP响应,将cookie返回给浏览器,浏览器下次再访问这台服务器的时候就会把这个cookie携带过去。
在这里插入图片描述

# -*- coding:utf-8 -*-from flask import Flask, request, make_responseapp = Flask(__name__)@app.route('/set_cookie')
def set_cookie():"""设置cookie:return: """resp = make_response('set cookie success')resp.set_cookie('user', 'zhangsan')return resp@app.route('/source')
def source():"""资源目录:return: """user = request.cookies.get('user')print(user)if not user:return '无权限'else:return '有权访问'if __name__ == '__main__':# 启动app, 开启调试模式app.run(debug=True)

浏览器端访问

在这里插入图片描述
在这里插入图片描述
设置简单cookie
访问 http://testsite.api:5000/set_cookie
在这里插入图片描述
在这里插入图片描述
设置好cookie之后,再次访问资源路径http://testsite.api:5000/source

这样就可以访问到资源了。
在这里插入图片描述
给cookie设置一些属性


#########  与上部分代码相同  ################@app.route('/set_cookie')
def set_cookie():"""设置cookie:return:"""resp = make_response('set cookie success')resp.set_cookie('user', 'zhangsan', max_age=30, path='/source', domain='testsite.api', httponly=True)return resp#########################

通过上面设置后的cookie:

  • 有效时长是30s
  • 设置路径是/source下面的,不能是其他路径,/content就访问不了
  • 只有域名testsite.api 有效
  • httponly 设置为True ,访问前端窃取cookie

浏览器操作cookie

原生js操作cookie

function setCookie(cname, cvalue, exdays) {var d = new Date();d.setTime(d.getTime() + (exdays*24*60*60*1000));// var expires = "expires="+ d.toUTCString();var expires = "expires="+ d.toGMTString();document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/;";
}
cookie设置的过期时间比较的是GMT时间
getTime() 方法获取19700101日午夜至今的毫秒数(GMT时间)
setTime() 的作用是设置日期对象,例如设置后的日期对象为:Thu Sep 17 2020 17:03:00 GMT+0800 (中国标准时间)。返回值是毫秒数。
toGMTString() 方法把日期对象转换为GMT时间字符串

jquery 操作cookie

<script src="https://cdn.staticfile.org/jquery/3.4.0/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/jquery-cookie/1.4.1/jquery.cookie.min.js"></script><script>
// 创建 cookie:
$.cookie('name', 'value');
// 创建 cookie,并设置 7 天后过期:
$.cookie('name', 'value', { expires: 7 });
</script>

cookie的缺点

cookie是不够安全的,很容易被黑客截获cookie,CSRF攻击就是利用了这个安全漏洞

session

在这里插入图片描述
步骤一:客户端把用户ID 和密码等登录信息放入报文的实体部分,通常是以POST 方法把请求发送给服务器。而这时,会使用HTTPS 通信来进行HTML 表单画面的显示和用户输入数据的发送。
步骤二:服务器会发放用以识别用户的Session ID。通过验证从客户端发送过来的登录信息进行身份认证,然后把用户的认证状态与Session ID 绑定后记录在服务器端。
向客户端返回响应时,会在首部字段Set-Cookie 内写入Session ID(如PHPSESSID=028a8c…)。
你可以把Session ID 想象成一种用以区分不同用户的等位号。然而,如果Session ID 被第三方盗走,对方就可以伪装成你的身份进行恶意操作了。因此必须防止Session ID 被盗,或被猜出。为了做到这点,Session ID 应使用难以推测的字符串,且服务器端也需要进行有效期的管理,保证其安全性。
另外,为减轻跨站脚本攻击(XSS)造成的损失,建议事先在Cookie 内加上httponly 属性。
步骤三:客户端接收到从服务器端发来的Session ID 后,会将其作为Cookie 保存在本地。下次向服务器发送请求时,浏览器会自动发送Cookie,所以Session ID 也随之发送到服务器。服务器端可通过验证接收到的Session ID 识别用户和其认证状态。

# -*- coding:utf-8 -*-from flask import Flask, sessionapp = Flask(__name__)app.secret_key = 'secret key string'@app.route('/set_session')
def set_session():"""设置session:return: """session['user'] = 'zhangsan'return 'set session success!'@app.route('/clear_session')
def clear_session():"""清理session:return: """session.clear()return 'clear session success!'@app.route('/source')
def source():"""资源:return: """if not session.get('user'):return '无权访问'return '有权访问'if __name__ == '__main__':app.run(debug=True)

不设置session访问资源
在这里插入图片描述
设置session
在这里插入图片描述
cookie中出现了session
再次访问资源
在这里插入图片描述
session的缺点

  • 占用服务器资源,降低效率
  • 因为依赖cookie,依然存在安全性问题
  • 分布式部署时,session共享是必须要考虑的

token

使用基于 Token 的身份验证方法,大概的流程是这样的:

  1. 客户端使用用户名跟密码请求登录
  2. 服务端收到请求,去验证用户名与密码
  3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
  4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
  6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据

总的来说就是客户端在首次登陆以后,服务端再次接收http请求的时候,就只认token了,请求只要每次把token带上就行了,服务器端会拦截所有的请求,然后校验token的合法性,合法就放行,不合法就返回401(鉴权失败)。

乍一看好像和前面的seesion-cookie有点像,seesion-cookie是通过seesionid来作为浏览器和服务端的链接桥梁,而token验证方式貌似是token来起到seesionid的角色。其实这两者差别是很大的。

  1. sessionid 他只是一个唯一标识的字符串,服务端是根据这个字符串,来查询在服务器端保持的seesion,这里面才保存着用户的登陆状态。但是token本身就是一种登陆成功凭证,他是在登陆成功后根据某种规则生成的一种信息凭证,他里面本身就保存着用户的登陆状态。服务器端只需要根据定义的规则校验这个token是否合法就行。
  2. session-cookie是需要cookie配合的,居然要cookie,那么在http代理客户端的选择上就是只有浏览器了,因为只有浏览器才会去解析请求响应头里面的cookie,然后每次请求再默认带上该域名下的cookie。但是我们知道http代理客户端不只有浏览器,还有原生APP等等,这个时候cookie是不起作用的,或者浏览器端是可以禁止cookie的(虽然可以,但是这基本上是属于吃饱没事干的人干的事)…,但是token 就不一样,他是登陆请求在登陆成功后再请求响应体中返回的信息,客户端在收到响应的时候,可以把他存在本地的cookie,storage,或者内存中,然后再下一次请求的请求头重带上这个token就行了。简单点来说cookie-session机制他限制了客户端的类型,而token验证机制丰富了客户端类型。
  3. 时效性。session-cookie的sessionid实在登陆的时候生成的而且在登出事时一直不变的,在一定程度上安全就会低,而token是可以在一段时间内动态改变的。
  4. 可扩展性。token验证本身是比较灵活的,一是token的解决方案有许多,常用的是JWT,二来我们可以基于token验证机制,专门做一个鉴权服务,用它向多个服务的请求进行统一鉴权。

jwt

概念
wt本质上就是一段加密字符串,里面存储了用户基本信息。token不需要存储在服务器端。广泛应用于前后端分离项目。
在这里插入图片描述
在项目开发中,一般会按照上图所示的过程进行认证,即:用户登录成功之后,服务端给用户浏览器返回一个token,以后用户浏览器要携带token再去向服务端发送请求,服务端校验token的合法性,合法则给用户看数据,否则,返回一些错误信息。

  • 传统token方式和jwt在认证方面有什么差异?

    • 传统token方式

    用户登录成功后,服务端生成一个随机token给用户,并且在服务端(数据库或缓存)中保存一份token,以后用户再来访问时需携带token,服务端接收到token之后,去数据库或缓存中进行校验token的是否超时、是否合法。

    • jwt方式

    用户登录成功后,服务端通过jwt生成一个随机token给用户(服务端无需保留token),以后用户再来访问时需携带token,服务端接收到token之后,通过jwt对token进行校验是否超时、是否合法。

原理
JWT是Auth0提出的通过对JSON进行加密签名来实现授权验证的方案,编码之后的JWT看起来是这样的一串字符:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

由 . 分为三段,通过解码可以得到

  1. 头部(Header)

包括类别(typ)、加密算法(alg);

{"alg": "HS256","typ": "JWT"
}

jwt的头部包含两部分信息:

  • 声明类型,这里是jwt
  • 声明加密的算法 通常直接使用 HMAC SHA256

然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分。

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

  1. 载荷(payload)

载荷就是存放有效信息的地方,这些有效信息包含三个部分

  • 标准中注册的声明
  • 公共的声明
  • 私有的声明

标准中注册的声明 (建议但不强制使用) :

  • iss: 该JWT的签发者,一般是服务器,是否使用是可选的;
  • iat(issued at): 在什么时候签发的(UNIX时间),是否使用是可选的;
  • exp(expires): 什么时候过期,这里是一个Unix时间戳,是否使用是可选的;
  • aud: 接收该JWT的一方,是否使用是可选的;
  • sub: 该JWT所面向的用户,userid,是否使用是可选的;

其他还有:

  • nbf (Not Before):如果当前时间在nbf里的时间之前,则Token不被接受;一般都会留一些余地,比如几分钟;,是否使用是可选的;
  • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

公共的声明 :
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.

私有的声明 :
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息,包括用户的一些基本信息。

举例

{"iss": "test server","iat": 1416797419,"exp": 1448333419,"aud": "terminal","sub": "user id","nickname": "goodspeed","username": "goodspeed","scopes": ["admin", "user"]
}

将上面的JSON对象进行base64编码可以得到下面的字符串。这个字符串我们将它称作JWT的Payload(载荷)。

eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE0MTY3OTc0MTksImV4cCI6MTQ0ODMzMzQxOSwiYXVkIjoid3d3Lmd1c2liaS5jb20iLCJzdWIiOiIwMTIzNDU2Nzg5Iiwibmlja25hbWUiOiJnb29kc3BlZWQiLCJ1c2VybmFtZSI6Imdvb2RzcGVlZCIsInNjb3BlcyI6WyJhZG1pbiIsInVzZXIiXX0

由于这里用的是可逆的base64 编码,所以第二部分的数据实际上是明文的。我们应该避免在这里存放不能公开的隐私信息。

  1. 签名(signature)

根据alg算法与私有秘钥进行加密得到的签名字串;

这一段是最重要的敏感信息,只能在服务端解密;

HMACSHA256(base64UrlEncode(header) + “.” + base64UrlEncode(payload), SECREATE_KEY)

jwt的第三部分是一个签证信息,这个签证信息由三部分组成:

  • header (base64后的)
  • payload (base64后的)
  • secret

这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

// javascript
var encodedString = base64UrlEncode(header) + ‘.’ + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, ‘secret’); // pq5IDv-yaktw6XEa5GEv07SzS9ehe6AcVSdTj0Ini4o
将这三部分用.连接成一个完整的字符串,构成了最终的jwt:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE0MTY3OTc0MTksImV4cCI6MTQ0ODMzMzQxOSwiYXVkIjoid3d3Lmd1c2liaS5jb20iLCJzdWIiOiIwMTIzNDU2Nzg5Iiwibmlja25hbWUiOiJnb29kc3BlZWQiLCJ1c2VybmFtZSI6Imdvb2RzcGVlZCIsInNjb3BlcyI6WyJhZG1pbiIsInVzZXIiXX0.pq5IDv-yaktw6XEa5GEv07SzS9ehe6AcVSdTj0Ini4o
签名的目的:

签名实际上是对头部以及载荷内容进行签名。所以,如果有人对头部以及载荷的内容解码之后进行修改,再进行编码的话,那么新的头部和载荷的签名和之前的签名就将是不一样的。而且,如果不知道服务器加密的密钥的话,得出来的签名也一定会是不一样的。
这样就能保证token不会被篡改。

优点

  • 因为json的通用性,所以JWT是可以进行跨语言支持的,像JAVA,JavaScript,NodeJS,PHP等很多语言都可以使用。
  • 因为有了payload部分,所以JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息。
  • 便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的。
  • 它不需要在服务端保存会话信息, 所以它易于应用的扩展

缺点

  • 安全性,由于jwt的payload是使用base64编码的,并没有加密,因此jwt中不能存储敏感数据。
  • 性能,jwt太长。由于是无状态使用JWT,所有的数据都被放到JWT里,如果还要进行一些数据交换,那载荷会更大,经过编码之后导致jwt非常长,cookie的限制大小一般是4k,cookie很可能放不下,所以jwt一般放在local
    storage里面。并且用户在系统中的每一次http请求都会把jwt携带在Header里面,http请求的Header可能比Body还要大。而sessionId只是很短的一个字符串,因此使用jwt的http请求比使用session的开销大得多。
  • 一次性,无状态是jwt的特点,但也导致了这个问题,jwt是一次性的。想修改里面的内容,就必须签发一个新的jwt。

token由于自包含信息,因此一般数据量较大,而且每次请求都需要传递,因此比较占带宽。另外,token的签名验签操作也会给cpu带来额外的负担。但是随着硬件的提升和带宽的提高,这些缺点变得越来越微不足道。

安全相关

  • 不应该在jwt的payload部分存放敏感信息,因为该部分是客户端可解密的部分。
  • 保护好secret私钥,该私钥非常重要。
  • 尽量使用https协议

生成jwt

可以自己拼接jwt字符串,也可以使用现有的库,一般开发中都会使用库

  • 安装pyjwt

pip install pyjwt==2.4.0
注意: 不同版本的pyjwt,提供的api可能不同。

  • 使用
# -*- coding:utf-8 -*-import jwt
import datetimeSECRET_KEY = 'iv%x6xo7l7_u9bf_u!9#g#m*)*=ej@bek5)(@u3kh*72+unjv='def create_token():"""生成json web token:return:"""# 构造headerheaders = {'typ': 'jwt','alg': 'HS256'}# 构造payloadpayload = {'user_id': 1,  # 自定义用户ID'username': 'zs',  # 自定义用户名'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=5)  # 超时时间}print(payload)result = jwt.encode(payload=payload, key=SECRET_KEY, algorithm="HS256", headers=headers)return resultdef get_payload(token):"""根据token获取payload:param token::return:"""try:verified_payload = jwt.decode(jwt=token, key=SECRET_KEY, algorithms=['HS256'])return verified_payloadexcept jwt.exceptions.ExpiredSignatureError:print('token已失效')except jwt.DecodeError:print('token认证失败')except jwt.InvalidTokenError:print('非法的token')if __name__ == '__main__':token = create_token()print(type(token))# <class 'str'>print(token)# eyJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6InpzIiwiZXhwIjoxNjYyNjkxMjc5fQ.21EiFPyo07Cn_DudXRYbjW-DX7-xT-FFy22u6x84gGApayload = get_payload(token)print(type(payload))# <class 'dict'>print(payload)

oauth2.0

OAuth 就是一种授权机制。数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据。系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使用。

举例:

快递员进入某小区需要密码,有门禁进不来,可以输入密码进入,但出于安全的考虑并不想告诉他密码。此时门禁有一个高级按钮“一键获取XXX授权”,只要业主这边同意,他会获取到一个有效期 n小时的令牌(token)正常出入。

授权方式
OAuth2.0 的授权简单理解其实就是获取令牌(access token)的过程,OAuth 协议定义了四种获得令牌的授权方式(authorization grant )如下:

授权码(authorization-code)

隐藏式(implicit)

密码式(password):

客户端凭证(client credentials)

不管我们使用哪一种授权方式,在三方应用申请令牌之前,都必须在系统中去申请身份唯一标识:客户端 ID(client ID)和 客户端密钥(client secret)。

比如要使用企业微信授权,则需要在企业微信平台注册一个企业,生成企业id和密钥,

授权码

授权码(authorization code)方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌。

这种方式是最常用的流程,安全性也最高,它适用于那些有后端的 Web 应用。授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌泄漏。

github授权登录
1,注册应用到github 设置回调url 设置完成得到client id和secret
在这里插入图片描述
使用client id获取code

https://github.com/login/oauth/authorize?client_id=4520e5d3f7afa74b26c0&redirect_uri=http://localhost:5000/customer/github/redirect

回调url获取到code http://localhost:5000/customer/github/redirect?code=XXX

根据code获取token

https://github.com/login/oauth/access_token?client_id={}&client_secret={}&code={}
拿到token获取用户

需设置请求头 即获取到的token
“Authorization”: access_token
https://api.github.com/user
用户认证

企业微信扫码登录
企业微信扫码登录举例请求方式: GET(HTTPS):

1,获取access token

使用企业id和密钥获取access token

请求地址: https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=ID&corpsecret=SECRET

2,获取code参数

请求地址:https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect

假设回调域为https://www.hyvdi.com/redirect 则授权同意侯会回调到https://www.hyvdi.com/redirect ?code=AUTH_CODE

3,用户身份认证

拿到access token 和 code 就可以获取用户信息 若存在则认证通过

请求地址:https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=ACCESS_TOKEN&code=CODE

具体流程:
在这里插入图片描述

企业微信接入文档

隐藏式

有些 Web 应用是纯前端应用,没有后端。这时就不能用上面的方式了,必须将令牌储存在前端,允许直接向前端颁发令牌。这种方式没有授权码这个中间步骤,所以称为(授权码)“隐藏式”(implicit)。

第一步,A 网站提供一个链接,要求用户跳转到 B 网站,授权用户数据给 A 网站使用。

https://b.com/oauth/authorize?response_type=token&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read

上面 URL 中,response_type参数为token,表示要求直接返回令牌。

第二步,用户跳转到 B 网站,登录后同意给予 A 网站授权。这时,B 网站就会跳回redirect_uri参数指定的跳转网址,并且把令牌作为 URL 参数,传给 A 网站。

https://a.com/oauth/callback?token=TOKEN

这种方式把令牌直接传给前端,是很不安全的。因此,只能用于一些安全要求不高的场景,并且令牌的有效期必须非常短,通常就是会话期间(session)有效,浏览器关掉,令牌就失效了。

密码式

如果你高度信任某个应用,直接告诉该应用。该应用就使用你的密码,申请令牌,这种方式称为"密码式"(password)。

第一步,A 网站要求用户提供 B 网站的用户名和密码。拿到以后,A 就直接向 B 请求令牌。

https://oauth.b.com/token? grant_type=password& username=USERNAME&
password=PASSWORD& client_id=CLIENT_ID

上面 URL 中,grant_type参数是授权方式,这里的password表示"密码式",username和password是 B 的用户名和密码。

第二步,B 网站验证身份通过后,直接给出令牌。注意,这时不需要跳转,而是把令牌放在 JSON 数据里面,作为 HTTP 回应,A 因此拿到令牌。

这种方式需要用户给出自己的用户名/密码,显然风险很大,因此只适用于其他授权方式都无法采用的情况,而且必须是用户高度信任的应用。

凭证式
凭证式(client credentials),适用于没有前端的命令行应用,即在命令行下请求令牌。

第一步,A 应用在命令行向 B 发出请求。

https://oauth.b.com/token? grant_type=client_credentials&
client_id=CLIENT_ID& client_secret=CLIENT_SECRET

上面 URL 中,grant_type参数等于client_credentials表示采用凭证式,client_id和client_secret用来让 B 确认 A 的身份。

第二步,B 网站验证通过以后,直接返回令牌。

这种方式给出的令牌,是针对第三方应用的,而不是针对用户的,即有可能多个用户共享同一个令牌。

缺点:

OAuth2是一个安全框架,描述了在各种不同场景下,多个应用之间的授权问题,不同应用实现方式不同。
OAuth2不是一个严格的标准协议,因此在实施过程中更容易出错。

优点:

授权token是短期的,到期会自动失效,用户自己无法修改。

授权token可以被数据所有者撤销,会立即失效,比如服务器删除某个token。

token有权限范围(scope),对于网络服务来说,只读令牌就比读写令牌更安全。

这些设计,保证了令牌既可以让第三方应用获得权限,同时又随时可控,不会危及系统安全。


http://chatgpt.dhexx.cn/article/c0RSo3Su.shtml

相关文章

笔记——什么是鉴权

前言 鉴权是自动化测试路上的拦路虎&#xff1b;故以此记录鉴权到底是怎么回事。 一、什么是鉴权&#xff0c;为什么要鉴权 鉴权&#xff1a;是指验证用户是否有访问系统的权利。为什么要鉴权 &#xff1a;对用户进行鉴权&#xff0c;防止非法用户占用网络资源&#xff0c;非…

ftok()函数解析

ftok 消息队列、信号灯、共享内存常用在Linux服务端编程的进程间通信环境中。而此三类编程函数在实际项目中都是用System V IPC函数实现的。System V IPC函数名称和说明如下表15-1所示。 表15-1 System V IPC函数 消息队列 信号灯 共享内存区 头文件 <sys/msg.h> …

ftok()函数的使用

在上一篇文章中&#xff0c;Mayuyu讲述了共享内存的原理以及使用方法。在创建共享内存之前&#xff0c;必须指定一个ID值&#xff0c;而这个ID值通常是通过现在要讲的ftok()函数得到。ftok()函数原型如下 其中参数fname是指定的文件名&#xff0c;这个文件必须是存在的而且可以…

linux ftok函数的使用

ftok API #include <sys/types.h> #include <sys/ipc.h> key_t ftok(const char *pathname, int proj_id); ftok根据路径名&#xff0c;提取文件信息&#xff0c;再根据这些文件信息及project ID合成key&#xff0c;该路径可以随便设置。该路径是必须存在的&#x…

ftok与fork

ftok函数编辑 系统建立IPC通讯 &#xff08; 消息队列、 信号量和 共享内存&#xff09; 时必须指定一个ID值。通常情况下&#xff0c;该id值通过ftok函数得到。 2ftok原型编辑 头文件 #include < sys/types.h> #include <sys/ipc.h> 函数原型&#xff1a; key_t f…

Linux下的ftok()函数

linux ftok&#xff08;&#xff09;函数 - 清清飞扬 - 博客园 (cnblogs.com) 系统建立IPC通讯&#xff08;如消息队列、共享内存时&#xff09;必须指定一个ID值。通常情况下&#xff0c;该id值通过ftok函数得到。 ftok原型如下&#xff1a; key_t ftok( char * fname, int i…

Linux中ftok函数介绍

函数原型&#xff1a; *key_t ftok(const char fname, int id); 功能&#xff1a;系统建立IPC通讯&#xff08;如消息队列&#xff0c;共享内存时&#xff09;必须指定一个ID值。通常情况下&#xff0c;该id值通过ftok函数得到 返回值&#xff1a;成功返回一个key_t值&#xf…

linux ftok()

系统建立IPC通讯&#xff08;如消息队列、共享内存时&#xff09;必须指定一个ID值。通常情况下&#xff0c;该id值通过ftok函数得到。 ftok原型如下&#xff1a; C代码 key_t ftok( char * fname, int id) key_t ftok( char * fname, int id) fname就时你指定的文件名&a…

Linux中ftok函数详解

在ipc通信中 system V 模式的ipc通信中都需要一个key值来生成对应的ID&#xff0c;那么key是如何生成的呢&#xff1f; 通过函数ftok生成 #include <sys/types.h>#include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id);参数&#xff1a; pathname: …

ftok说明

文章一&#xff1a; ftok函数 系统建立IPC通讯&#xff08;消息队列、信号量和共享内存&#xff09;时必须指定一个ID值。通常情况下&#xff0c;该id值通过ftok函数得到。 ftok原型 头文件&#xff1a; #include <sys/types.h> #include <sys/ipc.h> 如下&…

ftok()函数深度解析

关于ftok函数&#xff0c;先不去了解它的作用来先说说为什么要用它&#xff0c;共享内存&#xff0c;消息队列&#xff0c;信号量它们三个都是找一个中间介质&#xff0c;来进行通信的&#xff0c;这种介质多的是。就是怎么区分出来&#xff0c;就像唯一一个身份证来区分人一样…

linux进程间通信--消息队列相关函数(ftok)详解

ftok 消息队列、信号灯、共享内存常用在Linux服务端编程的进程间通信环境中。而此三类编程函数在实际项目中都是用System V IPC函数实现的。System V IPC函数名称和说明如下表15-1所示。 表15-1 System V IPC函数 消息队列 信号灯 共享内存区 头文件 <sys/msg.h> &l…

19-逆波兰表达式求值(栈)

逆波兰表达式求值 1.题目描述2. 思路3.代码实现3.1 c实现 4. 复杂度分析 1.题目描述 LeetCode题目链接 逆波兰表达式由波兰的逻辑学家卢卡西维兹提出。逆波兰表达式的特点是&#xff1a;没有括号&#xff0c;运算符总是放在和它相关的操作数之后。因此&#xff0c;逆波兰表达式…

逆波兰表达式求值

二元运算符的表达式定义为&#xff1a;(操作数) (运算符) (操作数) &#xff0c;其中操作数也可以为表达式。 在计算机中&#xff0c;根据运算符所在的不同位置来命名&#xff0c;表达式可以有如下三种不同的表示方法&#xff1a; 记表达式为&#xff1a;Exp S1 OP S2&a…

逆波兰表达式 c++

题目&#xff1a; 逆波兰表达式定义&#xff1a;1&#xff09;一个数是一个逆波兰表达式值为该数 2&#xff09;运算符 逆波兰表达式 逆波兰表达式 是其表达式&#xff0c;只有两个逆波兰表达式的值运算的结果 思路&#xff1a;用递归解决递归形式问题。 #include <iostr…

波兰表达式和逆波兰表达式

波兰表达式和逆波兰表达式 今天zxy的实验内容是关于逆波兰表达式的计算&#xff0c;刚好最近在做关于数据结构的习题&#xff0c;于是想着对波兰表达式和逆波兰表达式的转化和运算分别进行一个学习&#xff0c;于是写了这篇博客(有错的地方欢迎大家指出。) 常见的运算表达式&…

逆波兰表达式,走一波

逆波兰表达式又叫后缀表达式&#xff0c;中学时候学的那种表达式叫中缀表达式。 例如&#xff0c;5(63)3-1 &#xff0c; 3(4(21)2)-3 例子中的这两个式子&#xff0c;就是中缀表达式。下面这两个就是后缀表达式&#xff1a; 56331- &#xff0c; 342123- 中缀…

计算逆波兰表达式

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;数据结构。数据结构专栏主要是在讲解原理的基础上拿Java实现 ⭐码云地址超链接(Gitee)&#xff1a;这里存放我学…

JavaScript逆波兰表达式求值

逆波兰表达式简介 逆波兰表达式又叫做后缀表达式。逆波兰表示法是波兰逻辑学家J・卢卡西维兹(J・ Lukasiewicz)于1929年首先提出的一种表达式的表示方法 。后来,人们就把用这种表示法写出的表达式称作“逆波兰表达式”。逆波兰表达式把运算量写在前面,把算符写在后面。 逻辑提…

【题解】 逆波兰表达式

今天随机选题选到了这道题&#xff0c;这题比较经典&#xff0c;包含的知识点也不少&#xff0c;就在此与大家分享一下我的思路。 原题目&#xff1a;MFOJ P753-逆波兰表达式​​​​​ 题目描述 逆波兰记法中&#xff0c;操作符置于操作数的后面。例如表达“三加四”时&…