YONGFEIUALL

izheyi.com


  • Home

  • Archives

  • Categories

  • Tags

  • About

  • Search

Python给Jenkins Job批量修改权限

Posted on 2022-02-21 | In Automation Testing |

开发老是不自觉的更新UAT的Job,对测试造成一定的影响。查看了一下,Jenkins上的用户是通过第三方系统引入的,没有更合理的分组,用Role Based Strategy不能够实现对特定Job的权限控制。

采用项目矩阵授权策略来实现:目前的权限不受影响,只有UAT View下的Job只有测试能访问执行。

  1. 全局配置,设置Admin和Authenticated User权限

  2. 项目设置,选择不继承权限策略,并对特定用户加进来设置相应权限

这种方式,View下有很多个Job,每来一个人都要一个一个加,可以利用代码方式批量的来添加用户权限:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
s = jenkins.Jenkins(url=URL, username=USERNAME, password=PASSWORD)

jobs = s.get_jobs(view_name=VIEW_NAME)

for job in jobs:
name = job['name']
config = s.get_job_config(name)

content = f'''</permission>
<permission>hudson.model.Item.Build:{USER}</permission>
<permission>hudson.model.Item.Cancel:{USER}</permission>
<permission>hudson.model.Item.Configure:{USER}</permission>
<permission>hudson.model.Item.Delete:{USER}</permission>
<permission>hudson.model.Item.Move:{USER}</permission>
<permission>hudson.model.Item.Read:{USER}</permission>
<permission>hudson.model.Item.Workspace:{USER}</permission>
'''


new = config.replace('</permission>', content, 1)

s.reconfig_job(name, new)

Python给Gogs项目批量打Tag

Posted on 2021-10-21 | In Automation Testing |

Gogs的Rest API不能用,就用下面的方式来实现:

通过csv文件配置要打Tag的项目

1
Project Name,Release,Tag Name,Tag Branch,Title,Content
t1,Y,v1.1.0,master,,test1
t2,Y,v1.1.0,master,v1.1.0,test2
t3,Y,v1.1.0,master,v1.1.0,test3

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
session = HTMLSession()

# Get crsf token
r = session.get(url=f'{URL}/user/login')
csrf = r.html.xpath('//input[@name="_csrf"]/@value', first=True)

# Login
data = {
'_csrf': csrf,
'user_name': USERNAME,
'password': PASSWORD,
'login_source': 2
}
session.post(url=f'{URL}/user/login', data=data)

# Get login crsf token
r = session.get(url=f'{URL}')
login_csrf = r.html.xpath('//meta[@name="_csrf"]/@content', first=True)

# Set tag for project from csv file
projects = get_test_csv_data('build.csv')
for project in projects:
if project[1] == 'Y':

build_data = {
'tag_name': project[2],
'tag_target': project[3],
'title': project[4],
'content': project[5],
'_csrf': login_csrf
}

print(f'===== set tag {project[2]} for {project[0]} =====')
print(build_data)
r = session.post(url=f'{URL}/{OWNER}/{project[0]}/releases/new', data=build_data)

# Verify set correctly
try:
res = session.get(f'{URL}/{OWNER}/{project[0]}/releases')
version = res.html.xpath('//ul[@id="release-list"]//a', first=True).text
if version == project[2]:
print(f'===== set tag {project[2]} for {project[0]} successfully =====')
except:
print(f'===== set tag {project[2]} for {project[0]} failed =====')
print()

结果

1
2
3
4
5
6
7
8
9
10
11
===== set tag v1.1.0 for t1 =====
{'tag_name': 'v1.1.0', 'tag_target': 'master', 'title': '', 'content': 'test1', '_csrf': 'iE2XUTv0z4jDvjr6HuPYTiFvOrc6MTYzNTUwMDA3OTgyNjgxNTU5Mw=='}
===== set tag v1.1.0 for t1 failed =====

===== set tag v1.1.0 for t2 =====
{'tag_name': 'v1.1.0', 'tag_target': 'master', 'title': 'v1.1.0', 'content': 'test2', '_csrf': 'iE2XUTv0z4jDvjr6HuPYTiFvOrc6MTYzNTUwMDA3OTgyNjgxNTU5Mw=='}
===== set tag v1.1.0 for t2 successfully =====

===== set tag v1.1.0 for t3 =====
{'tag_name': 'v1.1.0', 'tag_target': 'master', 'title': 'v1.1.0', 'content': 'test3', '_csrf': 'iE2XUTv0z4jDvjr6HuPYTiFvOrc6MTYzNTUwMDA3OTgyNjgxNTU5Mw=='}
===== set tag v1.1.0 for t3 successfully =====

Python获得Gogs里项目最新发布版本Version

Posted on 2021-10-10 | In Automation Testing |

现在每个大版本号对应的各个项目的小版本号是不一致的,要快速的获得每次发布所对应的版本号。写个脚本来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
session = HTMLSession()

# Get crsf token
r = session.get(url=URL)
csrf = r.html.xpath('//input[@name="_csrf"]', first=True)

# Login
data = {
'_csrf': csrf.attrs.get('value'),
'user_name': USERNAME,
'password': PASSWORD,
'login_source': 2
}
session.post(url=URL, data=data)

# Get project latest release version
release_version = {}
for p in PROJECT_LIST:
res = session.get(f'https://{URL}/{p}/releases')

version = res.html.xpath('//ul[@id="release-list"]//a', first=True).text

release_version[p] = version

print(json.dumps(release_version, indent=4))

并通过API的方式,直接把相关信息填写到Confluence上。

1
2
3
4
5
con = Confluence(url=URL, username=USERNAME, password=PASSWORD)

body = '<div class="table-wrap"><table class="relative-table wrapped confluenceTable">版本信息</table></div>'
con.create_page(space='BDP', title='testtesttest', parent_id=85295571,
body=body)

最后,把脚本集成到Jenkins上,每次只要运行一下Job就可以快速完整版本号的整理工作。

FastAPI: JWT登录认证(20)

Posted on 2021-10-06 | In FastAPI |

至此,FastAPI的基本使用和整个流程都过完了。接下来看一下登录认证,是一个系统里最基本的功能,有些页面只能登录之后才能够访问。

有Session和Token两种方式实现,目前最流行的下面token方式:

  1. 用户登录后,返回一个token给前端,后台不存储该token
  2. 前端再带着这个token去访问需要登录的页面
  3. 后端根据token去判断用户,确定当前登录用户

    Bearer的简单OAuth2,前面已聊过FastAPI: Security(14),当时还没有生成token,OAuth2不能生成token,我们一般用JWT来实现

JWT

JWT全称是Json Web Token,JWT认证目前是前后端分离中非常流行的一种认证方式,生成的token分为三个部分: HEADER.PAYLOAD.SIGNATURE, 这三个部分都是可逆算法base64加密后的字符串, 最后用.拼接

  1. HEADER

    通常是加密算法

  2. PAYLOAD

    存储的自定义信息和token的过期时间

  3. SIGNATURE

    这个签证信息由三部分组成:

    • header (base64后的)
    • payload (base64后的)
    • secret (盐值(salt): 指的是加密时加入的自定义的字符串, 最好是随机或者杂乱的字符串, 这样更能够确定加密后字符串的唯一性, 可以使用settings中的SECRET_KEY)

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

python中有好几多库可以实现JWT认证,这里也用官网使用的python-jose,Python-jose需要一个额外的加密后端。这里我们使用的是推荐的后端:pyca/cryptography

1
pip install python-jose[cryptography]
生成token
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from jose import jwt
from datetime import datetime, timedelta

# 加密密钥
SECRET_KEY = "testjwt"

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

# exp 是固定写法必须得传 username和uid是自己存的值
to_encode = {"exp": expire, "username": "admin", "uid": "12345"}

# 生成token
token = jwt.encode(to_encode, SECRET_KEY, algorithm="HS256")
解密token
1
2
3
4
5
6
7
8
from jose.exceptions import ExpiredSignatureError, JWTError
try:
payload = jwt.decode(token, SECRET_KEY, algorithms="HS256" )
print(payload)
except ExpiredSignatureError as e:
print("token过期")
except JWTError as e:
print("token验证失败")

FastAPI实现JWT认证

  1. 加密解密的公共方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    def create_jwt_token(data: dict, expires_delta: Optional[timedelta] = None):
    to_encode = data.copy()
    if expires_delta:
    expire = datetime.utcnow() + expires_delta
    else:
    expire = datetime.utcnow() + timedelta(minutes=config.ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    token = jwt.encode(claims=to_encode, key=config.SECRET_KEY, algorithm=config.ALGORITHM)
    return token


    def decode_jwt_token(token: str):
    try:
    payload = jwt.decode(token=token, key=config.SECRET_KEY, algorithms=config.ALGORITHM)
    return payload
    except (jwt.JWTError, jwt.ExpiredSignatureError, AttributeError) as e:
    raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
    detail=f'access token failed: {e}',
    # 根据OAuth2规范, 认证失败需要在响应头中添加如下键值对
    headers={'WWW-Authenticate': "Bearer"}
    )
  1. 登录生成Token

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/login")

    @router.post('/api/login', tags=['users'])
    def user_login(username: str = Form(...), password: str = Form(...), db: Session = Depends(get_db)):
    db_user = crud.get_user_by_mail(db, username)
    if not db_user:
    raise HTTPException(status_code=404, detail="User not found")
    if password != db_user.hash_password:
    raise HTTPException(status_code=400, detail='passwod incorrect')

    data = {'email': db_user.email, 'user_id': db_user.id}
    token = jwttoken.create_jwt_token(data)

    return {"token": token, "token_type": "bearer"}

    @router.get('/current/user', tags=['users'])
    def get_current_user(token: Optional[str] = Header(...), db: Session = Depends(get_db)):
    payload = jwttoken.decode_jwt_token(token)
    email: str = payload.get("email")

    if email is None:
    raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
    detail=f'access token failed',
    # 根据OAuth2规范, 认证失败需要在响应头中添加如下键值对
    headers={'WWW-Authenticate': "Bearer"}
    )

    user = crud.get_user_by_mail(db, email=email)
    if user is None:
    raise HTTPException(status_code=404, detail="User not found")
    return user
  1. 验证Token

FastAPI: Docker部署(19)

Posted on 2021-10-06 | In FastAPI |

用Docker去部署应用已是目前最流行和通用的方式。现在把之前的项目部署到Docker上去。

准备Dockerfile

项目根目录下创建Dockerfile

1
2
3
4
5
6
7
8
9
10
11
FROM python:3.7

WORKDIR /fastapi

COPY ./requirements.txt /fastapi/requirements.txt

RUN pip install --no-cache-dir --upgrade -r /fastapi/requirements.txt

COPY . /fastapi/

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]

Build Docker Image

去到项目根目录下,执行下面命令

docker build -t myfastapi:user .

验证

1
PS E:\fastapi> docker image ls
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
myfastapi    user      0790ae3493a3   14 seconds ago   972MB

Start Docker Container

执行下面命令,部署应用到Container

docker run -d --name fastapiservice -p 80:80 myfastapi:user

验证

1
2
3
PS E:\fastapi> docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7b550b5a7ebb myfastapi:user "uvicorn main:app --…" About a minute ago Up About a minute 0.0.0.0:80->80/tcp fastapiservice

验证部署成功

FastAPI: 项目结构(18)

Posted on 2021-10-05 | In FastAPI |

如前言所述,开发一个项目,不可能所所有的文件都放到一个文件里,是需要有结构化的目录。

简单结构如下:

1
E:.
│  config.py
│  dependencies.py
│  main.py
│  requirements.txt
│
├─models
│  │  crud.py
│  │  database.py
│  │  models.py
│  │  schemas.py
│  │  __init__.py
│
├─routers
│  │  users.py
│  │  __init__.py
│
├─static
│      fastapi.jpg
│
├─templates
│  │  index.html
│
├─utils
│  │  __init__.py
  • models

    对数据库和数据的定义操作

  • routers

    路由控制,更好的按模块化划分系统功能实现

  • static

    引用的静态资源文件,js,css

  • templates

    前面页面的模板文件

  • dependencies

    系统所需的依赖项

  • main

    系统启动入口

  • config

    配置参数,连接数据等

  • utils

    公共的方法,E.g., JWT token的处理

  • requirements

    系统所依赖的外部库

项目请参见:github-fastapi

FastAPI: APIRouter(17)

Posted on 2021-10-05 | In FastAPI |

从前面的例子看,所有的Views操作都放在一个文件里,代码不易维护。为了更好的管理路径和代码,可以通过APIRouter来为该模块创建路径操作,给我们提供了在多个文件中注册路由的功能。

使用Router

在项目下创建routers -> users.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import List
from models import crud,schemas
from dependencies import get_db

router = APIRouter()


# 新建用户
@router.post("/users/", response_model=schemas.User, tags=['users'])
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
return crud.create_user(db, user=user)


# 通过id查询用户
@router.get("/user/{user_id}", response_model=schemas.User, tags=['users'])
def read_user(user_id: int, db: Session = Depends(get_db)):
db_user = crud.get_user(db, user_id=user_id)
if not db_user:
raise HTTPException(status_code=404, detail="User not found")
return db_user


# 所有用户
@router.get('/users/', response_model=List[schemas.User], tags=['users'])
def read_users(start: int=0, limit: int=10, db: Session = Depends(get_db)):
return crud.get_users(db, start, limit)

# Delete user
@router.delete('/user/{user_id}', response_model=schemas.User, tags=['users'])
def delete_user(user_id: int, db: Session = Depends(get_db)):
db_user = crud.delete_user(db, user_id=user_id)
if not db_user:
raise HTTPException(status_code=400, detail='User not found')
return db_user

# Update User
@router.put('/user/{user_id}', response_model=schemas.User, tags=['users'])
def update_user(user_id: int, update_user: schemas.UserUpdate, db: Session = Depends(get_db)):
db_user = crud.update_user(db, user_id=user_id, update_user=update_user)
if not db_user:
raise HTTPException(status_code=400, detail='User not found')
return db_user

注册Router

将我们的 APIRouter 注册到核心对象上去。main.py

1
2
3
4
5
6
7
8
9
10
# 导入 FastAPI
from fastapi import FastAPI
from routers import users
import uvicorn
import config

# 实例化 FastAPI
app = FastAPI()

app.include_router(users.router)

FastAPI: static file & template(16)

Posted on 2021-10-04 | In FastAPI |

合理的使用静态资源和页面模板,更好的来实现网站前后端分离。

静态资源通过aiofiles来实现。

简单理解,模板就是 web 后端向前端发送的 html 模型,还是jinia2来实现。

安装

1
2
3
pip install aiofiles

pip install jinja2

验证

  1. 在项目根目录下,创建static和templates文件夹。

  2. 在static下添加一个图片fastapi.jpg。

  3. 在templates下添加一个页面模板。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome</title>
    <link href="{{ url_for('static', path='/fastapi.jpg') }}" rel="stylesheet">
    </head>
    <body>
    <h1>Welcome: {{ username }}</h1>
    </body>
    </html>
  4. 接口返回html页面。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    from fastapi.responses import HTMLResponse
    from fastapi.staticfiles import StaticFiles
    from fastapi.templating import Jinja2Templates

    app.mount("/static", StaticFiles(directory="static"), name="static")

    templates = Jinja2Templates(directory="templates")

    # Return html page
    @app.get("/user/{user_id}", response_class=HTMLResponse)
    def read_user(request: Request, user_id: int, db: Session = Depends(get_db)):
    db_user = crud.get_user(db, user_id=user_id)
    if not db_user:
    raise HTTPException(status_code=404, detail="User not found")
    return templates.TemplateResponse('index.html', {'request': request, 'username': db_user.email})
  5. 结果

FastAPI: Mysql数据库操作(15)

Posted on 2021-10-04 | In FastAPI |

FastAPI可以通过SQLAlchemy将其轻松的适应于任何的数据库。SQLAlchemy是一个ORM(object-relational mapping)的框架。在ORM中,你创建一个类就会通过SQLAlchemy将其自动转成一张表,在类中的每一个属性就会将其转成表中的字段。

需要安装

1
pip install sqlalchemy
pip install pymysql

统一来管理数据库相关:

1
2
3
4
5
6
├─db
│ crud.py
│ database.py
│ models.py
│ schemas.py
│ __init__.py

database.py 数据库配置相关

在数据库相关的配置文件中,首先创建一个SQLAlchemy的”engine”,然后创建SessionLocal实例进行会话,最后创建模型类的基类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

SQLALCHEMY_DATABASE_URL = "mysql+pymysql://root:123456@127.0.0.1:3306/test"

engine = create_engine(
SQLALCHEMY_DATABASE_URL, encoding='utf8', echo=True
)

# SQLAlchemy中,CRUD是通过会话进行管理的,所以需要先创建会话,
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

# 创建基本映射类
Base = declarative_base()

models.py 数据库模型表

通过数据库配置文件中的基类来创建模型类。

1
2
3
4
5
6
7
8
9
10
from sqlalchemy import Boolean, Column, Integer, String
from database import Base


class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
email = Column(String(32), unique=True, index=True)
hash_password = Column(String(32))
is_active = Column(Boolean, default=True)

schemas.py 模型验证

定义请求参数模型验证与响应模型验证的Pydantic模型,其中响应模型中设置orm_mode=True参数,表示与ORM模型兼容,因为后续中返回的数据库查询是orm模型,通过设置这个参数可以将orm模型通过pydantic模型进行验证。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from pydantic import BaseModel


class UserBase(BaseModel):
email: str


class UserCreate(UserBase):
"""
请求模型验证:
email:
password:
"""

password: str

class UserUpdate(UserBase):
is_active: bool

class User(UserBase):
"""
响应模型:
id:
email:
is_active
并且设置orm_mode与之兼容
"""

id: int
is_active: bool

class Config:
orm_mode = True

crud.py 数据库操作相关

通过传入数据库连接以及参数等进行数据库操作,包括创建用户、查询用户等,返回的是orm模型对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from sqlalchemy.orm import Session
import models, schemas


# Get user by id
def get_user(db: Session, user_id: int):
return db.query(models.User).filter(models.User.id == user_id).first()

# Get all users
def get_users(db: Session, start: int=0, limit: int=10):
return db.query(models.User).offset(start).limit(limit).all()

# creae user
def create_user(db: Session, user: schemas.UserCreate):
fake_hashed_password = user.password + "notreallyhashed"
user = models.User(email=user.email, hash_password=fake_hashed_password)
db.add(user)
db.commit() # 提交保存到数据库中
db.refresh(user) # 刷新
return user

# Delete user
def delete_user(db: Session, user_id: int):
user = db.query(models.User).filter(models.User.id == user_id).first()
if user:
db.delete(user)
db.commit()
db.flush()
return user


# Update user
def update_user(db: Session, user_id: int, update_user: schemas.UserUpdate):
user = db.query(models.User).filter(models.User.id == user_id).first()
if user:
update_user = update_user.dict(exclude_unset=True)
for k, v in update_user.items():
setattr(user, k, v)
db.commit()
db.flush()
db.refresh(user)
return user

调用验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
Base.metadata.create_all(bind=engine) #数据库初始化,如果没有库或者表,会自动创建

# 实例化 FastAPI
app = FastAPI()

# Dependency
def get_db():
"""
每一个请求处理完毕后会关闭当前连接,不同的请求使用不同的连接
:return:
"""

db = SessionLocal()
try:
yield db
finally:
db.close()


# 新建用户
@app.post("/users/", response_model=schemas.User)
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
return crud.db_create_user(db=db, user=user)


# 通过id查询用户
@app.get("/user/{user_id}", response_model=schemas.User)
def read_user(user_id: int, db: Session = Depends(get_db)):
db_user = crud.get_user(db, user_id=user_id)
if not db_user:
raise HTTPException(status_code=404, detail="User not found")
return db_user

# 所有用户
@app.get('/users/', response_model=List[schemas.User])
def read_users(start: int=0, limit: int=10, db: Session = Depends(get_db)):
return crud.get_users(db, start, limit)

# Delete user
@app.delete('/user/{user_id}', response_model=schemas.User)
def delete_user(user_id: int, db: Session = Depends(get_db)):
db_user = crud.delete_user(db, user_id=user_id)
if not db_user:
raise HTTPException(status_code=400, detail='User not found')
return db_user

# Update User
@app.put('/user/{user_id}', response_model=schemas.User)
def update_user(user_id: int, update_user: schemas.UserUpdate, db: Session = Depends(get_db)):
db_user = crud.update_user(db, user_id=user_id, update_user=update_user)
if not db_user:
raise HTTPException(status_code=400, detail='User not found')
return db_user

DB:

1
2
3
4
5
6
7
8
9
10
mysql> desc users;
+---------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| email | varchar(32) | YES | UNI | NULL | |
| hash_password | varchar(32) | YES | | NULL | |
| is_active | tinyint(1) | YES | | NULL | |
+---------------+-------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

FastAPI: Security(14)

Posted on 2021-10-03 | In FastAPI |

安全,权限对于任何一个系统是不可避免的。

FastAPI提供了多种工具,可帮助你以标准的方式轻松、快速地处理安全性,而无需研究和学习所有的安全规范。

1
2
3
4
5
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

@app.get('/users/')
def users(token: str = Depends(oauth2_scheme)):
return {'token': token}

简单 Bear OAuth2实现完整流程

在FastAPI中, 提供了多种认证解决方案工具, 其中也包括了OAuth2, 可以使用OAuth2PasswordBearer类来实现OAuth2的功能, 使用的是OAuth2中的一种认证方案, 通过bearer token来携带token, 具体做法就是:

在请求头中添加参数Authorization, 其值为Bearer和token中间使用空格连接形成的字符串, 如Bearer your_token_string, 注意, Authorization和Bearer都是规范中固定的写法, 不可修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
fake_user = {
'admin':{
'username': 'admin',
'hash_password': 'fakehashadmin',
'enabled': True
}
}

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")# 这个参数的作用是当输入完用户密码后, 点击Authorize按钮后, 会请求127.0.0.1:8000/token这个网址, 把用户密码通过Form表单的形式传递给这个请求, 即这个/token就是我们网站的后台登录接口.


def fake_hash_password(password: str):
return "fakehash" + password

class User(BaseModel):
username: str
enbaled: Optional[bool] = None

class UserPwd(User):
hash_password: str


@app.post('/login')
def login(form: OAuth2PasswordRequestForm = Depends()):
user = fake_user.get(form.username)
if not user:
raise HTTPException(status_code=400, detail='user incorrect')
u = UserPwd(**user)
hashpwd = fake_hash_password(form.password)
if hashpwd != u.hash_password:
raise HTTPException(status_code=400, detail='passwod incorrect')

return {"access_token": u.username, "token_type": "bearer"}

12…40
唐胡璐

唐胡璐

i just wanna live while i am alive

393 posts
42 categories
74 tags
RSS
LinkedIn Weibo GitHub E-Mail
Creative Commons
© 2022 唐胡璐
Powered by Hexo
|
Theme — NexT.Pisces v5.1.4