新增用户密码加入请求校验,如果密码发生改变需要重新登陆,便于使用密码进行强制退出
This commit is contained in:
parent
3ccbc2c4b2
commit
953cdda006
@ -102,7 +102,8 @@ const save = async () => {
|
|||||||
const res = await postCurrentUserResetPassword(formData)
|
const res = await postCurrentUserResetPassword(formData)
|
||||||
if (res) {
|
if (res) {
|
||||||
elForm?.resetFields()
|
elForm?.resetFields()
|
||||||
ElMessage.success('保存成功')
|
authStore.logout()
|
||||||
|
ElMessage.warning('请重新登录')
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from .user import UserOut, UserUpdate, User, UserIn, UserSimpleOut, ResetPwd, UserUpdateBaseInfo
|
from .user import UserOut, UserUpdate, User, UserIn, UserSimpleOut, ResetPwd, UserUpdateBaseInfo, UserPasswordOut
|
||||||
from .role import Role, RoleOut, RoleIn, RoleOptionsOut, RoleSimpleOut
|
from .role import Role, RoleOut, RoleIn, RoleOptionsOut, RoleSimpleOut
|
||||||
from .menu import Menu, MenuSimpleOut, RouterOut, Meta, MenuTreeListOut
|
from .menu import Menu, MenuSimpleOut, RouterOut, Meta, MenuTreeListOut
|
||||||
from .dept import Dept, DeptSimpleOut, DeptTreeListOut
|
from .dept import Dept, DeptSimpleOut, DeptTreeListOut
|
||||||
|
@ -74,6 +74,12 @@ class UserSimpleOut(User):
|
|||||||
last_ip: str | None = None
|
last_ip: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class UserPasswordOut(UserSimpleOut):
|
||||||
|
model_config = ConfigDict(from_attributes=True)
|
||||||
|
|
||||||
|
password: str
|
||||||
|
|
||||||
|
|
||||||
class UserOut(UserSimpleOut):
|
class UserOut(UserSimpleOut):
|
||||||
model_config = ConfigDict(from_attributes=True)
|
model_config = ConfigDict(from_attributes=True)
|
||||||
|
|
||||||
|
@ -27,10 +27,10 @@ class OpenAuth(AuthValidation):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
async def __call__(
|
async def __call__(
|
||||||
self,
|
self,
|
||||||
request: Request,
|
request: Request,
|
||||||
token: Annotated[str, Depends(settings.oauth2_scheme)],
|
token: Annotated[str, Depends(settings.oauth2_scheme)],
|
||||||
db: AsyncSession = Depends(db_getter)
|
db: AsyncSession = Depends(db_getter)
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
每次调用依赖此类的接口会执行该方法
|
每次调用依赖此类的接口会执行该方法
|
||||||
@ -38,8 +38,8 @@ class OpenAuth(AuthValidation):
|
|||||||
if not settings.OAUTH_ENABLE:
|
if not settings.OAUTH_ENABLE:
|
||||||
return Auth(db=db)
|
return Auth(db=db)
|
||||||
try:
|
try:
|
||||||
telephone = self.validate_token(request, token)
|
telephone, password = self.validate_token(request, token)
|
||||||
user = await UserDal(db).get_data(telephone=telephone, v_return_none=True)
|
user = await UserDal(db).get_data(telephone=telephone, password=password, v_return_none=True)
|
||||||
return await self.validate_user(request, user, db, is_all=True)
|
return await self.validate_user(request, user, db, is_all=True)
|
||||||
except CustomException:
|
except CustomException:
|
||||||
return Auth(db=db)
|
return Auth(db=db)
|
||||||
@ -53,18 +53,18 @@ class AllUserAuth(AuthValidation):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
async def __call__(
|
async def __call__(
|
||||||
self,
|
self,
|
||||||
request: Request,
|
request: Request,
|
||||||
token: str = Depends(settings.oauth2_scheme),
|
token: str = Depends(settings.oauth2_scheme),
|
||||||
db: AsyncSession = Depends(db_getter)
|
db: AsyncSession = Depends(db_getter)
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
每次调用依赖此类的接口会执行该方法
|
每次调用依赖此类的接口会执行该方法
|
||||||
"""
|
"""
|
||||||
if not settings.OAUTH_ENABLE:
|
if not settings.OAUTH_ENABLE:
|
||||||
return Auth(db=db)
|
return Auth(db=db)
|
||||||
telephone = self.validate_token(request, token)
|
telephone, password = self.validate_token(request, token)
|
||||||
user = await UserDal(db).get_data(telephone=telephone, v_return_none=True)
|
user = await UserDal(db).get_data(telephone=telephone, password=password, v_return_none=True)
|
||||||
return await self.validate_user(request, user, db, is_all=True)
|
return await self.validate_user(request, user, db, is_all=True)
|
||||||
|
|
||||||
|
|
||||||
@ -83,23 +83,28 @@ class FullAdminAuth(AuthValidation):
|
|||||||
self.permissions = None
|
self.permissions = None
|
||||||
|
|
||||||
async def __call__(
|
async def __call__(
|
||||||
self,
|
self,
|
||||||
request: Request,
|
request: Request,
|
||||||
token: str = Depends(settings.oauth2_scheme),
|
token: str = Depends(settings.oauth2_scheme),
|
||||||
db: AsyncSession = Depends(db_getter)
|
db: AsyncSession = Depends(db_getter)
|
||||||
) -> Auth:
|
) -> Auth:
|
||||||
"""
|
"""
|
||||||
每次调用依赖此类的接口会执行该方法
|
每次调用依赖此类的接口会执行该方法
|
||||||
"""
|
"""
|
||||||
if not settings.OAUTH_ENABLE:
|
if not settings.OAUTH_ENABLE:
|
||||||
return Auth(db=db)
|
return Auth(db=db)
|
||||||
telephone = self.validate_token(request, token)
|
telephone, password = self.validate_token(request, token)
|
||||||
options = [joinedload(VadminUser.roles).subqueryload(VadminRole.menus), joinedload(VadminUser.depts)]
|
options = [joinedload(VadminUser.roles).subqueryload(VadminRole.menus), joinedload(VadminUser.depts)]
|
||||||
user = await UserDal(db).get_data(telephone=telephone, v_return_none=True, v_options=options, is_staff=True)
|
user = await UserDal(db).get_data(
|
||||||
|
telephone=telephone,
|
||||||
|
password=password,
|
||||||
|
v_return_none=True,
|
||||||
|
v_options=options,
|
||||||
|
is_staff=True
|
||||||
|
)
|
||||||
result = await self.validate_user(request, user, db, is_all=False)
|
result = await self.validate_user(request, user, db, is_all=False)
|
||||||
permissions = self.get_user_permissions(user)
|
permissions = self.get_user_permissions(user)
|
||||||
if permissions != {'*.*.*'} and self.permissions:
|
if permissions != {'*.*.*'} and self.permissions:
|
||||||
if not (self.permissions & permissions):
|
if not (self.permissions & permissions):
|
||||||
raise CustomException(msg="无权限操作", code=status.HTTP_403_FORBIDDEN)
|
raise CustomException(msg="无权限操作", code=status.HTTP_403_FORBIDDEN)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -39,27 +39,27 @@ from .validation.auth import Auth
|
|||||||
from utils.wx.oauth import WXOAuth
|
from utils.wx.oauth import WXOAuth
|
||||||
import jwt
|
import jwt
|
||||||
|
|
||||||
|
|
||||||
app = APIRouter()
|
app = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
@app.post("/api/login", summary="API 手机号密码登录", description="Swagger API 文档登录认证")
|
@app.post("/api/login", summary="API 手机号密码登录", description="Swagger API 文档登录认证")
|
||||||
async def api_login_for_access_token(
|
async def api_login_for_access_token(
|
||||||
request: Request,
|
request: Request,
|
||||||
data: OAuth2PasswordRequestForm = Depends(),
|
data: OAuth2PasswordRequestForm = Depends(),
|
||||||
db: AsyncSession = Depends(db_getter)
|
db: AsyncSession = Depends(db_getter)
|
||||||
):
|
):
|
||||||
user = await UserDal(db).get_data(telephone=data.username, v_return_none=True)
|
user = await UserDal(db).get_data(telephone=data.username, v_return_none=True)
|
||||||
|
error_code = status.HTTP_401_UNAUTHORIZED
|
||||||
if not user:
|
if not user:
|
||||||
raise CustomException(status_code=401, code=401, msg="该手机号不存在")
|
raise CustomException(status_code=error_code, code=error_code, msg="该手机号不存在")
|
||||||
result = VadminUser.verify_password(data.password, user.password)
|
result = VadminUser.verify_password(data.password, user.password)
|
||||||
if not result:
|
if not result:
|
||||||
raise CustomException(status_code=401, code=401, msg="手机号或密码错误")
|
raise CustomException(status_code=error_code, code=error_code, msg="手机号或密码错误")
|
||||||
if not user.is_active:
|
if not user.is_active:
|
||||||
raise CustomException(status_code=401, code=401, msg="此手机号已被冻结")
|
raise CustomException(status_code=error_code, code=error_code, msg="此手机号已被冻结")
|
||||||
elif not user.is_staff:
|
elif not user.is_staff:
|
||||||
raise CustomException(status_code=401, code=401, msg="此手机号无权限")
|
raise CustomException(status_code=error_code, code=error_code, msg="此手机号无权限")
|
||||||
access_token = LoginManage.create_token({"sub": user.telephone})
|
access_token = LoginManage.create_token({"sub": user.telephone, "password": user.password})
|
||||||
record = LoginForm(platform='2', method='0', telephone=data.username, password=data.password)
|
record = LoginForm(platform='2', method='0', telephone=data.username, password=data.password)
|
||||||
resp = {"access_token": access_token, "token_type": "bearer"}
|
resp = {"access_token": access_token, "token_type": "bearer"}
|
||||||
await VadminLoginRecord.create_login_record(db, record, True, request, resp)
|
await VadminLoginRecord.create_login_record(db, record, True, request, resp)
|
||||||
@ -68,10 +68,10 @@ async def api_login_for_access_token(
|
|||||||
|
|
||||||
@app.post("/login", summary="手机号密码登录", description="员工登录通道,限制最多输错次数,达到最大值后将is_active=False")
|
@app.post("/login", summary="手机号密码登录", description="员工登录通道,限制最多输错次数,达到最大值后将is_active=False")
|
||||||
async def login_for_access_token(
|
async def login_for_access_token(
|
||||||
request: Request,
|
request: Request,
|
||||||
data: LoginForm,
|
data: LoginForm,
|
||||||
manage: LoginManage = Depends(),
|
manage: LoginManage = Depends(),
|
||||||
db: AsyncSession = Depends(db_getter)
|
db: AsyncSession = Depends(db_getter)
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
if data.method == "0":
|
if data.method == "0":
|
||||||
@ -84,9 +84,14 @@ async def login_for_access_token(
|
|||||||
if not result.status:
|
if not result.status:
|
||||||
raise ValueError(result.msg)
|
raise ValueError(result.msg)
|
||||||
|
|
||||||
access_token = LoginManage.create_token({"sub": result.user.telephone, "is_refresh": False})
|
access_token = LoginManage.create_token(
|
||||||
|
{"sub": result.user.telephone, "is_refresh": False, "password": result.user.password}
|
||||||
|
)
|
||||||
expires = timedelta(minutes=settings.REFRESH_TOKEN_EXPIRE_MINUTES)
|
expires = timedelta(minutes=settings.REFRESH_TOKEN_EXPIRE_MINUTES)
|
||||||
refresh_token = LoginManage.create_token({"sub": result.user.telephone, "is_refresh": True}, expires=expires)
|
refresh_token = LoginManage.create_token(
|
||||||
|
payload={"sub": result.user.telephone, "is_refresh": True, "password": result.user.password},
|
||||||
|
expires=expires
|
||||||
|
)
|
||||||
resp = {
|
resp = {
|
||||||
"access_token": access_token,
|
"access_token": access_token,
|
||||||
"refresh_token": refresh_token,
|
"refresh_token": refresh_token,
|
||||||
@ -103,10 +108,10 @@ async def login_for_access_token(
|
|||||||
|
|
||||||
@app.post("/wx/login", summary="微信服务端一键登录", description="员工登录通道")
|
@app.post("/wx/login", summary="微信服务端一键登录", description="员工登录通道")
|
||||||
async def wx_login_for_access_token(
|
async def wx_login_for_access_token(
|
||||||
request: Request,
|
request: Request,
|
||||||
data: WXLoginForm,
|
data: WXLoginForm,
|
||||||
db: AsyncSession = Depends(db_getter),
|
db: AsyncSession = Depends(db_getter),
|
||||||
rd: Redis = Depends(redis_getter)
|
rd: Redis = Depends(redis_getter)
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
if data.platform != "1" or data.method != "2":
|
if data.platform != "1" or data.method != "2":
|
||||||
@ -129,9 +134,12 @@ async def wx_login_for_access_token(
|
|||||||
await UserDal(db).update_login_info(user, request.client.host)
|
await UserDal(db).update_login_info(user, request.client.host)
|
||||||
|
|
||||||
# 登录成功创建 token
|
# 登录成功创建 token
|
||||||
access_token = LoginManage.create_token({"sub": user.telephone, "is_refresh": False})
|
access_token = LoginManage.create_token({"sub": user.telephone, "is_refresh": False, "password": user.password})
|
||||||
expires = timedelta(minutes=settings.REFRESH_TOKEN_EXPIRE_MINUTES)
|
expires = timedelta(minutes=settings.REFRESH_TOKEN_EXPIRE_MINUTES)
|
||||||
refresh_token = LoginManage.create_token({"sub": user.telephone, "is_refresh": True}, expires=expires)
|
refresh_token = LoginManage.create_token(
|
||||||
|
payload={"sub": user.telephone, "is_refresh": True, "password": user.password},
|
||||||
|
expires=expires
|
||||||
|
)
|
||||||
resp = {
|
resp = {
|
||||||
"access_token": access_token,
|
"access_token": access_token,
|
||||||
"refresh_token": refresh_token,
|
"refresh_token": refresh_token,
|
||||||
@ -155,16 +163,20 @@ async def token_refresh(refresh: str = Body(..., title="刷新Token")):
|
|||||||
payload = jwt.decode(refresh, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
|
payload = jwt.decode(refresh, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
|
||||||
telephone: str = payload.get("sub")
|
telephone: str = payload.get("sub")
|
||||||
is_refresh: bool = payload.get("is_refresh")
|
is_refresh: bool = payload.get("is_refresh")
|
||||||
if telephone is None or not is_refresh:
|
password: str = payload.get("password")
|
||||||
|
if not telephone or not is_refresh or not password:
|
||||||
return ErrorResponse("未认证,请您重新登录", code=error_code, status=error_code)
|
return ErrorResponse("未认证,请您重新登录", code=error_code, status=error_code)
|
||||||
except jwt.exceptions.InvalidSignatureError:
|
except jwt.exceptions.InvalidSignatureError:
|
||||||
return ErrorResponse("无效认证,请您重新登录", code=error_code, status=error_code)
|
return ErrorResponse("无效认证,请您重新登录", code=error_code, status=error_code)
|
||||||
except jwt.exceptions.ExpiredSignatureError:
|
except jwt.exceptions.ExpiredSignatureError:
|
||||||
return ErrorResponse("登录已超时,请您重新登录", code=error_code, status=error_code)
|
return ErrorResponse("登录已超时,请您重新登录", code=error_code, status=error_code)
|
||||||
|
|
||||||
access_token = LoginManage.create_token({"sub": telephone, "is_refresh": False})
|
access_token = LoginManage.create_token({"sub": telephone, "is_refresh": False, "password": password})
|
||||||
expires = timedelta(minutes=settings.REFRESH_TOKEN_EXPIRE_MINUTES)
|
expires = timedelta(minutes=settings.REFRESH_TOKEN_EXPIRE_MINUTES)
|
||||||
refresh_token = LoginManage.create_token({"sub": telephone, "is_refresh": True}, expires=expires)
|
refresh_token = LoginManage.create_token(
|
||||||
|
payload={"sub": telephone, "is_refresh": True, "password": password},
|
||||||
|
expires=expires
|
||||||
|
)
|
||||||
resp = {
|
resp = {
|
||||||
"access_token": access_token,
|
"access_token": access_token,
|
||||||
"refresh_token": refresh_token,
|
"refresh_token": refresh_token,
|
||||||
|
@ -57,7 +57,8 @@ class AuthValidation:
|
|||||||
telephone: str = payload.get("sub")
|
telephone: str = payload.get("sub")
|
||||||
exp: int = payload.get("exp")
|
exp: int = payload.get("exp")
|
||||||
is_refresh: bool = payload.get("is_refresh")
|
is_refresh: bool = payload.get("is_refresh")
|
||||||
if telephone is None or is_refresh:
|
password: bool = payload.get("password")
|
||||||
|
if not telephone or is_refresh or not password:
|
||||||
raise CustomException(
|
raise CustomException(
|
||||||
msg="未认证,请您重新登录",
|
msg="未认证,请您重新登录",
|
||||||
code=status.HTTP_403_FORBIDDEN,
|
code=status.HTTP_403_FORBIDDEN,
|
||||||
@ -79,8 +80,8 @@ class AuthValidation:
|
|||||||
status_code=status.HTTP_403_FORBIDDEN
|
status_code=status.HTTP_403_FORBIDDEN
|
||||||
)
|
)
|
||||||
except jwt.exceptions.ExpiredSignatureError:
|
except jwt.exceptions.ExpiredSignatureError:
|
||||||
raise CustomException(msg="认证已过期,请您重新登录", code=cls.error_code, status_code=cls.error_code)
|
raise CustomException(msg="认证已失效,请您重新登录", code=cls.error_code, status_code=cls.error_code)
|
||||||
return telephone
|
return telephone, password
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def validate_user(cls, request: Request, user: VadminUser, db: AsyncSession, is_all: bool = True) -> Auth:
|
async def validate_user(cls, request: Request, user: VadminUser, db: AsyncSession, is_all: bool = True) -> Auth:
|
||||||
|
@ -35,7 +35,7 @@ class WXLoginForm(BaseModel):
|
|||||||
|
|
||||||
class LoginResult(BaseModel):
|
class LoginResult(BaseModel):
|
||||||
status: bool | None = False
|
status: bool | None = False
|
||||||
user: schemas.UserOut | None = None
|
user: schemas.UserPasswordOut | None = None
|
||||||
msg: str | None = None
|
msg: str | None = None
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
@ -87,6 +87,6 @@ class LoginValidation:
|
|||||||
await count.delete()
|
await count.delete()
|
||||||
self.result.msg = "OK"
|
self.result.msg = "OK"
|
||||||
self.result.status = True
|
self.result.status = True
|
||||||
self.result.user = schemas.UserSimpleOut.model_validate(user)
|
self.result.user = schemas.UserPasswordOut.model_validate(user)
|
||||||
await crud.UserDal(db).update_login_info(user, request.client.host)
|
await crud.UserDal(db).update_login_info(user, request.client.host)
|
||||||
return self.result
|
return self.result
|
||||||
|
Loading…
x
Reference in New Issue
Block a user