This commit is contained in:
王思川 2022-11-01 14:02:58 +08:00
parent f8541f7c63
commit 1cdef195ec
18 changed files with 226 additions and 90 deletions

View File

13
AccessPolicies/crud.py Normal file
View File

@ -0,0 +1,13 @@
from sqlalchemy.orm import Session
from AccessPolicies import schemas, models
from Utils.UniqueCoder.TimeSerialNumUtils import create_time_serial_num
def create_policy(db: Session, body: schemas.PolicyBase):
item = models.Policy(**body.dict())
item.id = create_time_serial_num(prefix="p", suffix="")
db.add(item)
db.commit()
db.refresh(item)
return item

16
AccessPolicies/models.py Normal file
View File

@ -0,0 +1,16 @@
from sqlalchemy import Column, String
from Utils.DataBase.SqlAlchemyUtils import Base
class Policy(Base):
__tablename__ = "policy"
id = Column(String(64), primary_key=True, index=True)
ptype = Column(String(4), comment="策略类型")
v0 = Column(String(255), comment="主体 sub")
v1 = Column(String(255), comment="对象 obj")
v2 = Column(String(255), comment="动作 act")
v3 = Column(String(255), nullable=True)
v4 = Column(String(255), nullable=True)
v5 = Column(String(255), nullable=True)

View File

@ -0,0 +1,36 @@
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from AccessPolicies import models, schemas, crud
from Utils.AccessControl.AccessUtil import ac_admin
from Utils.DataBase.SqlAlchemyUtils import engine, get_db
models.Base.metadata.create_all(bind=engine)
router = APIRouter(
tags=["访问策略"],
prefix="/api/user/access_policy",
dependencies=[
Depends(ac_admin)
]
)
@router.post("/create", response_model=schemas.Policy, summary="新建访问策略")
def create(body: schemas.PolicyBase, db: Session = Depends(get_db)):
return crud.create_policy(db=db, body=body)
@router.post("/delete", summary="删除访问策略")
def delete():
pass
@router.post("/edit", summary="编辑访问策略")
def delete():
pass
@router.post("/view", summary="查看访问策略")
def delete():
pass

30
AccessPolicies/schemas.py Normal file
View File

@ -0,0 +1,30 @@
from enum import Enum
from typing import Optional
from pydantic import BaseModel
class PtypeEnum(Enum):
enum1 = "p"
enum2 = "g"
enum3 = "g2"
class PolicyBase(BaseModel):
ptype: PtypeEnum
v0: str
v1: str
v2: str
v3: Optional[str] = None
v4: Optional[str] = None
v5: Optional[str] = None
class Config:
use_enum_values = True
class Policy(PolicyBase):
id: str
class Config:
orm_mode = True

View File

@ -3,16 +3,31 @@ from werkzeug.security import generate_password_hash
from sqlalchemy.orm import Session
from Utils.EncryptProcess import EncyptUtil
from Utils.UniqueCoder.TimeSerialNumUtils import create_time_serial_num
from . import models, schemas
def get_user_by_name(db: Session, name: str):
return db.query(models.User).filter(models.User.name == name).first()
return db.query(models.User).with_entities(
models.User.id,
models.User.name,
models.User.email,
models.User.role,
models.User.depart,
models.User.is_active
).filter(models.User.name == name).first()
def get_user_by_id(db: Session, uid: int):
return db.query(models.User).filter(models.User.id == uid).first()
def get_user_by_id(db: Session, uid: str):
return db.query(models.User).with_entities(
models.User.id,
models.User.name,
models.User.email,
models.User.role,
models.User.depart,
models.User.is_active
).filter(models.User.id == uid).first()
def get_user_by_email(db: Session, email: str):
@ -31,7 +46,7 @@ def get_users(db: Session, body: schemas.UserSearch, skip, limit):
def create_user(db: Session, body: schemas.UserCreate):
body.passwd = generate_password_hash(body.passwd)
body.passwd = generate_password_hash(EncyptUtil.decrypt_data(encrypt_msg=body.passwd))
item = models.User(**body.dict())
item.id = create_time_serial_num(prefix="UID", suffix="")
db.add(item)
@ -40,19 +55,19 @@ def create_user(db: Session, body: schemas.UserCreate):
return item
def delete_user(db: Session, _id: int):
db.query(models.User).filter_by(id=_id).delete()
def delete_user(db: Session, uid: str):
db.query(models.User).filter_by(id=uid).delete()
db.commit()
return True
def edit_user(db: Session, uid: int, body: schemas.UserEdit):
def edit_user(db: Session, uid: str, body: schemas.UserEdit):
db.query(models.User).filter_by(id=uid).update(body.dict())
db.commit()
return True
def reset_user_pwd(db: Session, uid: int, passwd: schemas.PasswdRegex):
def reset_user_pwd(db: Session, uid: str, passwd: schemas.PasswdRegex):
passwd = generate_password_hash(passwd)
db.query(models.User).filter_by(id=uid).update({"passwd": passwd})
db.commit()

View File

@ -2,6 +2,15 @@ from User import crud, schemas
from Utils.DataBase.SqlAlchemyUtils import Session
ROOT_USER = {
"email": "wangsichuan@fecr.com.cn",
"passwd": "Fecr1988",
"name": "root",
"role": "admin",
"depart": "数字化部"
}
def default_root():
db = Session()
@ -9,13 +18,7 @@ def default_root():
if not data:
root = {
"email": "wangsichuan@fecr.com.cn",
"passwd": "Fecr1988.",
"name": "root",
"role": "admin",
"depart": "数字化部"
}
root = ROOT_USER
crud.create_user(db=db, body=schemas.UserCreate(**root))

View File

@ -1,6 +1,6 @@
from datetime import timedelta
from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, HTTPException, Header
from sqlalchemy.orm import Session
from werkzeug.security import check_password_hash
@ -37,15 +37,38 @@ def login(body: schemas.UserLogin, db: Session = Depends(get_db)):
}
access_token_expires = timedelta(minutes=Config.ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = TokenUtil.create_token(
data=user, expires_delta=access_token_expires
)
access_token = TokenUtil.create_token(data=user, expires_delta=access_token_expires)
refresh_token_expires = timedelta(minutes=Config.REFRESH_TOKEN_EXPIRE_MINUTES)
refresh_token = TokenUtil.create_refresh_token(uid=data.id, expires_delta=refresh_token_expires)
user.update({"token": access_token})
user.update({"refresh_token": refresh_token})
return user
@router.get("/detail", summary="用户信息")
def detail():
pass
def detail(token: str = Header(...), db: Session = Depends(get_db)):
uid = TokenUtil.get_uid_from_token(token)
data = crud.get_user_by_id(db=db, uid=uid)
if data is None:
raise HTTPException(status_code=404, detail="User Not found")
return data
@router.post("/refresh_token", summary="更新token")
def to_refresh_token(refresh_token: str = Header(...), db: Session = Depends(get_db)):
decoded_token = TokenUtil.decode_token(refresh_token)
uid = decoded_token.get("uid")
data = crud.get_user_by_id(db=db, uid=uid)
if not data:
return {"info": "User Not Existed"}
user = {**data}
access_token_expires = timedelta(minutes=Config.ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = TokenUtil.create_token(data=user, expires_delta=access_token_expires)
return {"token": access_token}

View File

@ -4,7 +4,7 @@ from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from User import crud, models, schemas
from User.default import default_root
from User.default import default_root, ROOT_USER
from Utils.DataBase.SqlAlchemyUtils import engine, get_db
from Utils.AccessControl.AccessUtil import ac_admin
@ -29,14 +29,14 @@ def create_user(body: schemas.UserCreate, db: Session = Depends(get_db)):
return {"info": "Success"}
@router.post("/delete", summary="删除用户")
def delete_user(uid: int, db: Session = Depends(get_db)):
crud.delete_user(db=db, _id=uid)
@router.post("/delete/{uid}", summary="删除用户")
def delete_user(uid: str, db: Session = Depends(get_db)):
crud.delete_user(db=db, uid=uid)
return {"info": "Success"}
@router.post("/edit", summary="编辑用户")
def user_edit(uid: int, body: schemas.UserEdit, db: Session = Depends(get_db)):
@router.post("/edit/{uid}", summary="编辑用户")
def user_edit(uid: str, body: schemas.UserEdit, db: Session = Depends(get_db)):
data = crud.get_user_by_id(db, uid)
if not data:
raise HTTPException(status_code=400, detail="User Not found")
@ -44,25 +44,25 @@ def user_edit(uid: int, body: schemas.UserEdit, db: Session = Depends(get_db)):
return {"info": "Success"}
@router.post("/reset_pwd", summary="重置用户密码")
def user_reset_pwd(uid: int, db: Session = Depends(get_db)):
@router.post("/reset_pwd/{uid}", summary="重置用户密码")
def user_reset_pwd(uid: str, db: Session = Depends(get_db)):
data = crud.get_user_by_id(db, uid)
if not data:
raise HTTPException(status_code=400, detail="User Not found")
passwd = "Fecr1988"
passwd = ROOT_USER.get("passwd")
crud.reset_user_pwd(db=db, passwd=passwd, uid=uid)
return {"info": "Success"}
@router.get("/detail/{uid}", summary="用户信息")
def detail(uid: str, db: Session = Depends(get_db)):
data = crud.get_user_by_id(db=db, uid=uid)
if data is None:
raise HTTPException(status_code=404, detail="User Not found")
return data
@router.post("/search", summary="查询用户", response_model=List[schemas.User])
def search_users(body: schemas.UserSearch, skip: int = 0, limit: int = 20, db: Session = Depends(get_db)):
users = crud.get_users(db, body=body, skip=skip, limit=limit)
return users
@router.post("/detail", summary="用户详情", response_model=schemas.User)
def user_detail(uid: int, db: Session = Depends(get_db)):
data = crud.get_user_by_id(db, uid=uid)
if data is None:
raise HTTPException(status_code=404, detail="User Not found")
return data

View File

@ -1,27 +1,27 @@
import os
from typing import Optional
import casbin
from fastapi import HTTPException, status, Request, Header
from fastapi import HTTPException, Header
from Utils.Authentication.TokenUtil import decode_token
e = casbin.Enforcer(
os.getcwd() + r"\Utils\AccessControl\model.conf",
os.getcwd() + r"\Utils\AccessControl\policy.csv"
)
def ac_admin(token: Optional[str] = Header(...)):
role = decode_token(token).get("user_info").get("role")
if role != "admin":
raise HTTPException(status_code=400, detail="No Access")
def access_interseptor(request: Request, token: Optional[str] = Header(...)):
sub = decode_token(token).get("role")
obj = request.url.__str__().split(request.base_url.__str__()[:-1])[-1].split("?")[0]
act = request.method
if not e.enforce(sub, obj, act):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="No Access",
headers={"WWW-Authenticate": "Bearer"},
)
raise credentials_exception
# def ac_index_store(request: Request, token: Optional[str] = Header(...)):
# e = casbin.Enforcer(
# os.getcwd() + r"\Utils\AccessControl\model.conf",
# os.getcwd() + r"\Utils\AccessControl\policy_index_store.csv"
# )
#
# sub = decode_token(token).get("role")
# obj = request.url.__str__().split(request.base_url.__str__()[:-1])[-1].split("?")[0]
# act = request.method
#
# if not e.enforce(sub, obj, act):
# raise HTTPException(status_code=400, detail="No Access")

View File

@ -1,15 +1,15 @@
# Request definition
[request_definition]
r = sub, obj, act
# Policy definition
[policy_definition]
p = sub, obj, act
# Policy effect
[role_definition]
g = _, _
g2 = _, _
[policy_effect]
e = some(where (p.eft == allow))
# Matchers
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act || r.sub == "admin"

View File

@ -1,8 +0,0 @@
p, admin, /api/user/admin/create, POST
p, admin, /api/user/admin/delete, POST
p, admin, /api/user/admin/edit, POST
p, admin, /api/user/admin/search, POST
p, admin, /api/user/admin/detail, POST
p, user, /api/user/detail, POST
p, user, /api/user/change_pwd, POST
1 p admin /api/user/admin/create POST
2 p admin /api/user/admin/delete POST
3 p admin /api/user/admin/edit POST
4 p admin /api/user/admin/search POST
5 p admin /api/user/admin/detail POST
6 p user /api/user/detail POST
7 p user /api/user/change_pwd POST

View File

@ -1,3 +1,4 @@
SECRET_KEY = "HpGXrdwbL73ZPgQC"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 * 30
ACCESS_TOKEN_EXPIRE_MINUTES = 10
REFRESH_TOKEN_EXPIRE_MINUTES = 60 * 24 * 30

View File

@ -18,7 +18,7 @@ def create_token(*, data: dict, expires_delta: timedelta = None):
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
expire = datetime.utcnow() + timedelta(minutes=5)
to_encode.update({"exp": expire})
# Token编码
@ -26,26 +26,33 @@ def create_token(*, data: dict, expires_delta: timedelta = None):
return encoded_jwt
def create_refresh_token(uid: str, expires_delta: timedelta = None):
to_encode = dict()
to_encode.update({"uid": uid})
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=60)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, Config.SECRET_KEY, algorithm=Config.ALGORITHM)
return encoded_jwt
def decode_token(token: str):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid Token",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, Config.SECRET_KEY, algorithms=[Config.ALGORITHM])
except jwt.exceptions.ExpiredSignatureError:
raise HTTPException(status_code=201, detail="Token Has Expired")
except PyJWTError:
raise credentials_exception
raise HTTPException(status_code=401, detail="Invalid Token")
return payload
async def get_token_header(authorization: str = Header(...)):
"""
获取Token并验证
:param authorization:
:return: uid
"""
token = authorization.split(' ')[-1] # 获取token
openid = decode_token(token) # 验证token
if not openid:
raise HTTPException(status_code=400, detail="无效Token")
def get_uid_from_token(token: str):
uid = decode_token(token).get("user_info").get("uid")
return uid

View File

View File

View File

@ -16,4 +16,4 @@ app.add_middleware(
app.include_router(router_user.router)
app.include_router(router_user_admin.router)
app.include_router(router_policy.router)
# app.include_router(router_policy.router)