Creation and verification of python-fastapi-token

JWT token authentication login

The previous blog talked about obtaining and verifying request parameters. In practice, this one will demonstrate a basic JWT authentication. Our company uses two token verification methods, one request token, one refresh token, and token expiration time. Short, dedicated to request data, refresh token is dedicated to refresh expired request token.

jwt official website https://jwt.io/

If you still don’t understand JWT, you need to take a good look at the knowledge of JWT. JWT authentication is currently a very popular authentication method in the separation of front-end and back-end: It is composed of three sections. The first section is usually an encryption algorithm, and the second section is The custom information you store (anyone who is not encrypted can go to https://jwt.io/ to see the data) The third paragraph is the signature parameters generated in the first and second paragraphs to ensure that the token has not been modified

Generate Token

Dependent library

Python currently has several libraries to implement jwt verification

  • python-jose
  • pyjwt
  • jwcrypto
  • authlib

No comparison demonstration here, just pick one

Shell

pip install python-jose

Simple demo

 

from datetime import datetime, timedelta

from jose import jwt

# 加密密钥 这个很重要千万不能泄露了
SECRET_KEY = "kkkkk"

# 设置过期时间 现在时间 + 有效时间    示例5分钟
expire = datetime.utcnow() + timedelta(minutes=5)

# exp 是固定写法必须得传  sub和uid是自己存的值
to_encode = {"exp": expire, "sub": str(123), "uid": "12345"}

# 生成token 
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm="HS256")
print(encoded_jwt) 
# eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTU1MDg5MzQsInN1YiI6IjEyMyIsInVpZCI6IjEyMzQ1In0.lttAYe808lVQgGhL9NXei2bbC1LIGs-SS0l6qfU_QxU

You can copy it to https://jwt.io/ to solve it and see

Insert picture description here

Insert picture description here

 

Decrypt token

payload = jwt.decode(
            "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTU1MDg5MzQsInN1YiI6IjEyMyIsInVpZCI6IjEyMzQ1In0.lttAYe808lVQgGhL9NXei2bbC1LIGs-SS0l6qfU_QxU",
            SECRET_KEY, algorithms="HS256"
        )
print(payload)
# {'exp': 1595508934, 'sub': '123', 'uid': '12345'}

The correct way to decrypt

The above method is when the token is correct and it has not expired, it will be solved normally. Now add common exception capture.

from jose.exceptions import ExpiredSignatureError, JWTError
try:
    payload = jwt.decode(
                "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTU1MDk0ODQsInN1YiI6IjEyMyIsInVpZCI6IjEyMzQ1In0.deulPSOPfON-lfbXtvQfTfc-DwqvFoQqv7Y1BhMecBw",
                SECRET_KEY, algorithms="HS256"
            )
    print(payload)
# 当然两个异常捕获也可以写在一起,不区分
except ExpiredSignatureError as e:
    print("token过期")
except JWTError as e:
    print("token验证失败")

Realize JWT authentication login in FastAPI

The above-mentioned jwt encryption and decryption process is clear. This step is very simple. First, create a security.pyfile dedicated to encryption and decryption.

from datetime import datetime, timedelta
from typing import Any, Union, Optional
from jose import jwt
from fastapi import Header
# 导入配置文件
from setting import config

ALGORITHM = "HS256"


def create_access_token(
    subject: Union[str, Any], expires_delta: timedelta = None
) -> str:
    """
    # 生成token
    :param subject: 保存到token的值
    :param expires_delta: 过期时间
    :return:
    """
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(
            minutes=config.ACCESS_TOKEN_EXPIRE_MINUTES
        )
    to_encode = {"exp": expire, "sub": str(subject)}
    encoded_jwt = jwt.encode(to_encode, config.SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt


def check_jwt_token(
     token: Optional[str] = Header(None)
) -> Union[str, Any]:
    """
    解析验证 headers中为token的值 担任也可以用 Header(None, alias="Authentication") 或者 alias="X-token"
    :param token:
    :return:
    """

    try:
        payload = jwt.decode(
            token,
            config.SECRET_KEY, algorithms=[ALGORITHM]
        )
        return payload
    except (jwt.JWTError, jwt.ExpiredSignatureError, AttributeError):
        # 抛出自定义异常, 然后捕获统一响应
        raise custom_exc.TokenAuthError(err_desc="access token fail")

The above must be defined, the way to encrypt and decrypt the token, this step is to log in to generate the token

# 从刚刚定义好jwt的文件导入生成方法
from security import create_access_token
from pydantic import BaseModel


class UserInfo(BaseModel):
    username: str
    password: str


@router.post("/login/access-token", summary="用户登录认证")
async def login_access_token(
        *,
        db: Session = Depends(deps.get_db),
        user_info: UserInfo,
) -> Any:
    """
    用户登录
    :param db:
    :param user_info:
    :return:
    """

    # 验证用户账号密码是否正确
     user = curd_user.authenticate(db, email=user_info.username, password=user_info.password)
    if not user:
        logger.info(f"用户邮箱认证错误: email{user_info.username} password:{user_info.password}")
        return response_code.resp_500(message="用户名或者密码错误")
    elif not curd_user.is_active(user):
        return response_code.resp_500(message="用户邮箱未激活")

    # 如果用户正确通过 则生成token
    # 设置过期时间
    access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)

    # 登录token 只存放了user.id
    return response_code.resp_200(data={
        "token": create_access_token(user.id, expires_delta=access_token_expires),
    })

Verification token

This step is used from fastapi import Dependsto validate the headers tokenin the above security.pytoken parameter definition has taken the file headers

from typing import Any, Union

from fastapi import Depends
# 从刚刚定义好jwt的文件导入解密方法
from security import check_jwt_token

@router.get("/user/info", summary="获取用户信息", response_model=user.UserInfo)
async def get_user_info(
    token_data: Union[str, Any] = Depends(check_jwt_token)  
) -> Any:
    """
    获取用户信息
    :param token_data:
    :return:
    """
    print(token_data)
    # 这个状态能响应说明token验证通过
    return response_code.resp_200(data={
        "username": "用户信息"
    })

So the correct request method should be like this. Carry the token field in the headers. If you repeat it again, you can also check_jwt_tokenalias the token in the method. The most common one is Authenticationwhy not write Authenticationit directly in the check_jwt_token parameter ? Because the parameter is written as a capital letter and does not start with a capital letter. It conforms to the Python programming pep8 specification, and that is X-Token, the variable does not support -symbols, so it is written as an alias.

import requests

res = requests.get("http://127.0.0.1:8000/user/info", headers={
    "token": "xxxx",
    "content-type": "application/json"
})

to sum up

Familiar with the jwt token generation and decryption method in the first half, you can apply it in any Python framework (Django, Flask, Tornado, Sanic, Bottle, etc.). Many encapsulated extensions are essentially the same. Generally, I don’t like to use extensions.

Jwt authentication is actually very simple. To figure out the process of encryption and decryption, it is enough to understand the principle a little bit. With redis later, you can complete operations such as single sign-on. There is also the issue of token renewal. For example, you are writing a blog, and the token is invalid before the blog is finished. When the result is submitted, the token authentication fails, and the token heartbeat detection renewal is required.

Complete code GitHub address

My own FastAPI project generator https://github.com/CoderCharm/fastapi-mysql-generator

GitHub https://github.com/CoderCharm/FastAdmin/blob/master/backend/app/api/api_v1/auth/views.py#L32


Author: Wang Right

Article link: https://www.charmcode.cn/article/2020-07-23_fastapi_jwt

Copyright statement: Keke want to use a prostitution article? The copyright of this article belongs to the author, please indicate the source in any form of reprint. https://www.charmcode.cn !

FastAPI


Source: charmcode.cn
Author: Wang Right
article link: https://www.charmcode.cn/article/2020-07-23_fastapi_jwt
Keke want white prostitute article? The copyright of this article belongs to the author, please indicate the source in any form of reprint.

Guess you like

Origin blog.csdn.net/weixin_42100456/article/details/109139023