oauth2.0 如何验证在FastAPI中作为HttpOnly Cookie发送的JWT?

2ledvvac  于 2022-12-03  发布在  其他
关注(0)|答案(1)|浏览(170)

问题

我正在开发一个FastAPI应用程序,该应用程序要求对用户访问的某些端点进行身份验证,我正在使用FastAPI的Oauth2和Jose为身份验证过程创建JWT,看来确保令牌在前端受到保护的最好方法是将它们存储在HttpOnly Cookie中。我一直在努力理解如何正确地通过HttpOnly Cookie传递JWT,以便FastAPI服务器能够验证头中的JWT。目前,当我尝试将JWT标记作为HttpOnly Cookie传递时,我得到一个401 Unauthorized Error
我尝试过的
当我将JWT标记作为模板字符串编码到头中时,我已经能够成功地使用该标记对用户进行身份验证,但是,当我将JWT作为Cookie通过头传递给FastAPI服务器时,我的FastAPI服务器无法对用户进行身份验证,并返回401 unauthorized error. I'为了更好地理解这两个场景之间的不同之处,我尝试查看了网络选项卡,以查看在我的请求中发送到FastApi服务器的报头是什么。

代码成功示例

当我将JWT作为模板字符串传递并得到200响应时,这是在标头中:
身份验证:承载令牌

async function getPosts() {
    const url = "http://localhost:8000/posts";
    const fetchConfig = {
      headers: {
        Authorization: `Bearer ${tokenValue}`,
      },
    };
    const response = await fetch(url, fetchConfig);
    const posts = await response.json();
  }

不成功的代码示例

当我将JWT作为HttpOnly Cookie传递并获得401响应时,这是在标头中:
Cookie:访问令牌=“不记名令牌”
我也尝试过改变我在服务器上设置cookie的方式,使头看起来像这样:
Cookie:身份验证=“不记名令牌”

async function getPosts() {
    const url = "http://localhost:8000/posts";
    const fetchConfig = {
      credentials: "include",
    };
    const response = await fetch(url, fetchConfig);
    const posts = await response.json();
    console.log(posts);
  }

快速API代码

下面是保护API端点的Oauth2令牌验证的代码,它基于FastAPI文档中的示例:FastApi Oauth2

oauth2_scheme = OAuth2PasswordBearer(tokenUrl='login')

SECRET_KEY = settings.SECRET_KEY
ALGORITHM = settings.ALGORITHM
ACCESS_TOKEN_EXPIRE_MINUTES = settings.ACCESS_TOKEN_EXPIRE_MINUTES

def verify_access_token(token: str, credentials_exception):
  try:
    payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
    id: str = payload.get("user_id")
    if id is None:
      raise credentials_exception
    token_data = schemas.TokenData(id=id)
  
  except JWTError:
    raise credentials_exception

  return token_data

def get_current_user(token: str = Depends(oauth2_scheme), db: Session = Depends(database.get_db)):
  credentials_exception = HTTPException(
    status_code=status.HTTP_401_UNAUTHORIZED,
    detail=f"Could not validate credentials",
    headers={"WWW-Authenticate": "Bearer"}
  )

  token = verify_access_token(token, credentials_exception)
  user = db.query(models.User).filter(models.User.id == token.id).first()

  return user

下面是一个受保护端点的示例,它依赖于上面列出的oauth2文件中的get_current_user函数。

@router.get("/", response_model=List[schemas.PostOut])
def get_posts(db: Session = Depends(get_db), current_user: int = Depends(oauth2.get_current_user):
  return {"Message": "Protected Endpoint Reached"}

看起来我遇到了这个问题,因为Oauth2中的get_current_user函数只能在JWT为以下格式时从头中获取JWT:
身份验证:承载令牌
当令牌为以下格式之一时,似乎无法从标头验证令牌:
Cookie:访问令牌=“不记名令牌”
Cookie:身份验证=“不记名令牌”
当我通过HttpOnly Cookie发送标头时,我是否需要以某种方式更改发送标头的方式,或者我是否需要更改get_current_user函数的某些内容,使其能够正确读取Cookie标头。
任何建议都非常感谢,感谢您抽出时间阅读本文!

ctzwtxfj

ctzwtxfj1#

若要从Cookie而不是Authorization信头(OAuth2PasswordBearer的预设值)取得Token,请使用tell FastAPI that you want the token to originate from a cookie instead

def get_current_user(access_token: str = Cookie(...), db: Session = Depends(database.get_db)):

这假定标记已命名为access_token(而不仅仅是标记)。根据需要调整名称。

相关问题