在Go IRIS中使用JWT

在Go IRIS中使用JWT

1. 跨域认证

互联网服务离不开用户认证,一种认证方式是:

1、用户向服务器发送用户名和密码。

2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。

3、服务器向用户返回一个 session_id,写入用户的 Cookie。

4、用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。

5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。

这种模式的问题在于,扩展性(scaling)不好。单机当然没有问题,如果是服务器集群,或者是跨域的服务导向架构,就要求 session 数据共享,每台服务器都能够读取 session。

2. 关于JWT

JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且独立的方式,可以在各方之间作为JSON对象安全地传输信息。 此信息可以通过数字签名进行验证和信任。JWT可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。

JWT 的原理是,服务器认证以后,生成一个 JSON 对象,发回给用户,就像下面这样。

{
    
  "name":    name, // 用户名
  "exp":      time.Now().Add(time.Hour * 2).Unix(), // 添加过期时间
}

以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名。

服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。

实际的 JWT 大概就像下面这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTk4MDMyODEsInBhc3N3b3JkIjoiMTIzMyIsInBob25lIjoiMTU5MDIwMTUwNDMifQ.NvKsiKh37pxmRH4inKb32EXT-XkSfIC96nEX7p1RLag

它是一个很长的字符串,中间用点(.)分隔成三个部分:Header.Payload.Signature

  • Header(头部):一个 JSON 对象,描述 JWT 的元数据,一般如下所示:
{
   
  "alg": "HS256",
  "typ": "JWT"
}

alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型࿰

在FastAPI创建和使用JWT(JSON Web Tokens)通常涉及以下步骤: 1. 安装所需的库:首先,需要安装`fastapi`、`pydantic`以及用于处理JWT的`python-jose`和`passlib`库。 2. 创建用户模型:定义一个用户模型类来表示用户的信息,可以使用`pydantic`的`BaseModel`。 3. 创建JWT令牌的工具函数:定义一个函数来生成JWT令牌,这个函数通常需要用户的标识信息(比如ID)和一个密钥(secret key)。 4. 创建登录API端点:创建一个API端点,用户可以通过这个端点提交登录信息。如果登录成功,返回一个JWT令牌。 5. 验证JWT令牌:创建一个间件或者依赖项,用于在用户访问需要认证的API端点时验证JWT令牌的有效性。 6. 使用JWT令牌保护API端点:在需要保护的API端点上使用上面创建的验证机制,确保只有提供有效JWT令牌的用户才能访问。 下面是一个简单的示例代码: ```python from fastapi import FastAPI, Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jose import JWTError, jwt from pydantic import BaseModel from datetime import datetime, timedelta from passlib.context import CryptContext # 为示例简单起见,这里使用硬编码的密钥 SECRET_KEY = "your_secret_key" ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = 30 class Token(BaseModel): access_token: str token_type: str class User(BaseModel): username: str class UserInDB(User): hashed_password: str pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") fake_users_db = { "johndoe": { "username": "johndoe", "hashed_password": pwd_context.hash("secret"), } } def verify_password(plain_password, hashed_password): return pwd_context.verify(plain_password, hashed_password) def get_user(db, username: str): if username in db: user_dict = db[username] return UserInDB(**user_dict) def authenticate_user(fake_db, username: str, password: str): user = get_user(fake_db, username) if not user or not verify_password(password, user.hashed_password): return False return user def create_access_token(data: dict, expires_delta: timedelta = None): to_encode = data.copy() if expires_delta: expire = datetime.utcnow() + expires_delta else: expire = datetime.utcnow() + timedelta(minutes=15) to_encode.update({"exp": expire}) encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) return encoded_jwt app = FastAPI() @app.post("/token", response_model=Token) async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()): user = authenticate_user(fake_users_db, form_data.username, form_data.password) if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect username or password", headers={"WWW-Authenticate": "Bearer"}, ) access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) access_token = create_access_token( data={"sub": user.username}, expires_delta=access_token_expires ) return {"access_token": access_token, "token_type": "bearer"} @app.get("/users/me") async def read_users_me(current_user: User = Depends(oauth2_scheme)): return current_user ``` 在这个示例,我们定义了一个`/token`端点用于登录并获取JWT令牌,以及一个`/users/me`端点用于返回当前用户的信息,这个端点使用了`oauth2_scheme`依赖项来验证JWT令牌。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值