changes
This commit is contained in:
parent
f8541f7c63
commit
1cdef195ec
|
@ -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
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
31
User/crud.py
31
User/crud.py
|
@ -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()
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"
|
|
@ -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,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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue