def update_email_by_token(self, db: Session, response: Response, *, obj_in: schema_user.UserUpdateEmailIn): """ 绑定/更换 邮箱 :param email: 邮箱 :param email_code: 邮箱验证码 :return: 用户信息, 提示信息 """ # --------- 校验邮箱是否已被使用 --------- # email_user = crud_user.get_user_by_email(db, email=obj_in.email) if email_user: message = f"邮箱 {obj_in.email} 已被使用" response.status_code = status.HTTP_400_BAD_REQUEST return None, message # --------- 校验邮箱验证码 ---------# redis_email_code = redis_client.get(obj_in.email) if obj_in.email_code != redis_email_code: message = "验证码不正确或已过期" response.status_code = status.HTTP_422_UNPROCESSABLE_ENTITY return None, message # --------- 绑定/更换 邮箱 --------- # db_user_obj = crud_user.update_email_by_id(db, id=token_user.id, email=obj_in.email) if not db_user_obj: message = "邮箱更新失败" response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR logger.error(message) else: redis_client.set(obj_in.email, "", ex=1) message = "邮箱更新成功" response.status_code = status.HTTP_200_OK return db_user_obj, message
def logoff(self, db: Session, response: Response, *, decode_token: dict): """ 用户注销 :param decode_token: 解析之后的 token :return: 用户信息, 提示信息 """ # --------- 获取当前用户信息 ----------- # db_user, message = self.jwt_token_auth(db, response, decode_token=decode_token) if not db_user: return None, message # --------- 注销用户)-------- # userid = db_user.id db_logoff_user = crud_user.logoff(db, id=userid, is_logoff=1) # 逻辑注销 0:未注销,1:已注销 if not db_logoff_user: message = "用户注销失败" response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR logger.error(message) else: redis_client.set(userid, "", ex=1) message = "用户注销成功" response.status_code = status.HTTP_200_OK return db_logoff_user, message
def signout(self, response: Response, *, decode_token: dict): """ 退出登录 :param decode_token: 解析之后的 token :return: 用户id, 提示信息 """ redis_userid = decode_token.get("sub") # 获取 redis 中存储对应的 key(userid) redis_client.set(redis_userid, "", ex=1) message = "退出登录成功" response.status_code = status.HTTP_200_OK return redis_userid, message
def retrieve_password_by_account( self, db: Session, response: Response, *, account: str, obj_in: schema_user.UserRetrievePasswordIn): """ 通过账号(手机号/邮箱)找回密码 :param account: 手机号/邮箱 :param verify_code: 验证码 :param password: 密码 :return: 用户信息, 提示信息 """ # ----------- 判断输入账号是 手机号/邮箱 ---------- # if re.match(RE_PHONE, account): # 手机 db_user = crud_user.get_user_by_phone(db, phone=account) elif re.match(RE_EMAIL, account): # 邮箱 db_user = crud_user.get_user_by_email(db, email=account) else: message = "账号输入有误" response.status_code = status.HTTP_422_UNPROCESSABLE_ENTITY return None, message if not db_user: message = f"账号 {account} 未注册" response.status_code = status.HTTP_404_NOT_FOUND logger.error(message) return None, message if db_user.status == 1: message = f"账号 {account} 已被禁用" response.status_code = status.HTTP_403_FORBIDDEN else: # ----------- 校验验证码 ---------- # redis_verify_code = redis_client.get(account) if obj_in.verify_code != redis_verify_code: message = "验证码不正确或已过期" response.status_code = status.HTTP_401_UNAUTHORIZED return None, message # ---------- 重新设置密码 ---------- # hashed_new_password = security.get_password_hash(obj_in.password) db_user_obj = crud_user.update_password_by_id( db, id=db_user.id, hashed_password=hashed_new_password) if not db_user_obj: message = "找回密码失败" response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR else: redis_client.set(db_user.id, "", ex=1) redis_client.set(account, "", ex=1) message = "找回密码成功" response.status_code = status.HTTP_200_OK return db_user_obj, message logger.error(message) return None, message
async def get_client_code(*, response: Response) -> Optional[str]: """ 获取 客户端 验证码 \n return: 状态码, 邮箱验证码, 提示信息 """ client_code = "".join(random.sample(string.hexdigits, k=6)) # 自动生成6位随机字符(客户端验证码) if not client_code: message = "客户端验证码获取失败" response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR return response_code.resp_error(message=message) else: client_code_time = settings.CLIENT_CODE_EXPIRE_SECONDS // 60 message = f"客户端验证码获取成功, {client_code_time}分钟之内有效" response.status_code = status.HTTP_200_OK redis_client.set(client_code, client_code, ex=settings.CLIENT_CODE_EXPIRE_SECONDS) return response_code.resp_ok(data={"client_code": client_code}, message=message)
def update_phone_by_token(self, db: Session, response: Response, *, decode_token: dict, obj_in: schema_user.UserUpdatePhoneIn): """ 绑定/更换 手机号 :param decode_token: 解析之后的 token :param phone: 手机号 :param phone_code: 手机验证码 :return: 用户信息, 提示信息 """ # --------- 校验手机号是否已被使用 --------- # phone_user = crud_user.get_user_by_phone(db, phone=obj_in.phone) if phone_user: message = f"手机号 {obj_in.phone} 已被使用" response.status_code = status.HTTP_400_BAD_REQUEST return None, message # --------- 校验手机验证码 ---------# redis_phone_code = redis_client.get(obj_in.phone) if obj_in.phone_code != redis_phone_code: message = "验证码不正确或已过期" response.status_code = status.HTTP_422_UNPROCESSABLE_ENTITY return None, message # --------- 绑定/更换 手机号 --------- # db_user_obj = crud_user.update_phone_by_id(db, id=phone_user.id, phone=obj_in.phone) if not db_user_obj: message = "手机号更新失败" response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR logger.error(message) else: redis_client.set(obj_in.phone, "", ex=1) message = "手机号更新成功" response.status_code = status.HTTP_200_OK return db_user_obj, message
async def get_verify_code( *, response: Response, account: Optional[str] = Query(...)) -> Optional[str]: """ 获取 手机/邮箱 验证码 \n account: 手机/邮箱 \n return: 状态码, 提示信息 """ random_code = "".join(random.sample(string.digits, k=6)) # 自动生成6位随机数(手机/邮箱验证码) code = None if re.match(RE_PHONE, account): # 手机号 phone_code, message = verify_code.get_phone_code( phone=account, phone_code=random_code) if phone_code: code = phone_code redis_client.set( account, phone_code, ex=settings.PHONE_CODE_EXPIRE_SECONDS) # 存储手机验证码于 redis 中 elif re.match(RE_EMAIL, account): # 邮箱 email_code, message = verify_code.get_email_code( email=account, email_code=random_code) if email_code: code = email_code redis_client.set( account, email_code, ex=settings.EMAIL_CODE_EXPIRE_SECONDS) # 存储邮箱验证码于 redis 中 else: message = "账号信息格式不正确" response.status_code = status.HTTP_422_UNPROCESSABLE_ENTITY logger.error(message) return response_code.resp_error(message=message) if not code: response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR return response_code.resp_error(message=message) response.status_code = status.HTTP_200_OK return response_code.resp_ok(message=message)
def change_password_by_token(self, db: Session, response: Response, *, decode_token: dict, obj_in: schema_user.UserChangePasswordIn): """ 通过 token 设置初始/修改 密码 :param decode_token: 解析之后的 token :param old_password: 原始密码(如果用户未设置初始密码,则不用填) :param new_password: 新密码 :return: 状态码, 用户信息, 提示信息 """ # --------- 获取当前用户信息 ----------- # db_user, message = self.jwt_token_auth(db, response, decode_token=decode_token) if not db_user: return None, message # ---------- 修改密码 ------------ # if db_user.hashed_password: # 判断用户是否设置过初始密码 if not security.verify_password(obj_in.old_password, db_user.hashed_password): # 校验原始密码 message = "原始密码不正确" response.status_code = status.HTTP_401_UNAUTHORIZED return None, message hashed_new_password = security.get_password_hash(obj_in.new_password) db_user_obj = crud_user.update_password_by_id( db, id=db_user.id, hashed_password=hashed_new_password) if not db_user_obj: message = "密码修改失败" response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR logger.error(message) else: message = "密码修改成功" response.status_code = status.HTTP_200_OK redis_client.set(db_user.id, "", ex=1) return db_user_obj, message
async def items_test( *, bar: str = Query(..., title="测试字段", description="测试字段描述"), db: Session = Depends(deps.get_db), ) -> Any: """ 用户登录 :param bar: :param db: :return: """ # 测试redis使用 redis_client.set("test_items", bar, ex=60) redis_test = redis_client.get("test_items") # 用不惯orm查询的可以直接sql(建议把CURD操作单独放到service文件夹下,统一管理) test_sql = "SELECT nickname,avatar from sys_user WHERE id>=:id" admin_user_res = db.execute(text(test_sql), {"id": 1}).fetchall() return response_code.resp_200(data={ "items": "ok", "admin_user_info": admin_user_res, "redis_test": redis_test })
def signup(self, db: Session, request: Request, response: Response, *, obj_in: schema_user.UserSignupIn): """ 通过 手机号/邮箱 注册 :param account: 手机号/邮箱 :param verify_code: 验证码 :param password: 密码 :return: 用户信息, 提示信息 """ # --------- 校验验证码 --------- # redis_verify_code = redis_client.get(obj_in.account) if obj_in.verify_code != redis_verify_code: message = "验证码不正确或已过期" response.status_code = status.HTTP_422_UNPROCESSABLE_ENTITY return None, message # --------- 先查询一次,在进行注册 -------- # if re.match(RE_PHONE, obj_in.account): # 手机号 db_user = crud_user.get_user_by_phone(db, phone=obj_in.account) if db_user: message = f"账号 {obj_in.account} 已被注册" response.status_code = status.HTTP_400_BAD_REQUEST return None, message else: dict_obj_in = { "phone": obj_in.account, "hashed_password": security.get_password_hash(obj_in.password), "ip": request.client.host } db_create_user = crud_user.create_by_phone( db, obj_in=dict_obj_in) # 通过手机号进行注册 elif re.match(RE_EMAIL, obj_in.account): # 邮箱 db_user = crud_user.get_user_by_email(db, email=obj_in.account) if db_user: message = f"账号 {obj_in.account} 已被注册" response.status_code = status.HTTP_400_BAD_REQUEST return None, message else: dict_obj_in = { "email": obj_in.account, "hashed_password": security.get_password_hash(obj_in.password), "ip": request.client.host } db_create_user = crud_user.create_by_email( db, obj_in=dict_obj_in) # 通过邮箱进行注册 else: message = "账号输入有误" # 用户名 response.status_code = status.HTTP_422_UNPROCESSABLE_ENTITY logger.error(message) return None, message if not db_create_user: message = f"用户 {obj_in.account} 注册失败" response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR logger.error(message) else: message = f"用户 {obj_in.account} 注册成功" response.status_code = status.HTTP_201_CREATED redis_client.set(obj_in.account, "", ex=1) # 注册成功之后使验证码立即失效 return db_create_user, message
def signin_by_verify_code(self, db: Session, request: Request, response: Response, *, obj_in: schema_user.UserVerifyCodeSigninIn): """ 通过 短信/邮箱 验证码登录 :param account: 手机号/邮箱/用户名 :param verify_code: 验证码 :return: token, 提示信息 """ # --------- 比较验证码是否匹配 ----------- # redis_verify_code = redis_client.get(obj_in.account) if obj_in.verify_code != redis_verify_code: message = "验证码不正确或已过期" response.status_code = status.HTTP_422_UNPROCESSABLE_ENTITY logger.error(message) return None, message if re.match(RE_PHONE, obj_in.account): # 手机 db_user = crud_user.get_user_by_phone(db, phone=obj_in.account) elif re.match(RE_EMAIL, obj_in.account): # 邮箱 db_user = crud_user.get_user_by_email(db, email=obj_in.account) else: message = "账号输入有误,请重新输入" response.status_code = status.HTTP_422_UNPROCESSABLE_ENTITY logger.error(message) return None, message # ----------- 判断账号是否注册过 ----------- # userid = None authorityid = None if not db_user: if re.match(RE_PHONE, obj_in.account): # 手机 dict_obj_in = { "phone": obj_in.account, "hashed_password": None, "ip": request.client.host } db_user_obj = crud_user.create_by_phone(db, obj_in=dict_obj_in) elif re.match(RE_EMAIL, obj_in.account): # 邮箱 dict_obj_in = { "email": obj_in.account, "hashed_password": None, "ip": request.client.host } db_user_obj = crud_user.create_by_email(db, obj_in=dict_obj_in) if not db_user_obj: message = "登录失败" response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR logger.error(message) return None, message userid = db_user_obj.id # 将新增之后的 用户id 赋值给变量 authorityid = db_user_obj.authorityid # 默认权限 elif db_user.status == 1: message = f"账号 {obj_in.account} 已被禁用" response.status_code = status.HTTP_403_FORBIDDEN logger.error(message) return None, message if db_user: userid = db_user.id authorityid = db_user.authorityid # -------- # 登录token 存储了userid 和 authorityid ------- # access_token_expires = timedelta( minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) token = security.create_access_token( userid, authorityid, expires_delta=access_token_expires) redis_client.set(userid, token, ex=settings.ACCESS_TOKEN_EXPIRE_MINUTES) # --------- 登录成功之后向数据库添加一条登录日志信息 ---------- # ip = request.client.host # 用户ip signin_log_id = crud_user.add_signin_log(db, userid=userid, ip=ip) if not signin_log_id: message = f"用户 {obj_in.account} 登录失败" response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR logger.error(message) return None, message else: redis_client.set(obj_in.account, "", ex=1) # 使验证码失效 message = f"用户 {obj_in.account} 登录成功" response.status_code = status.HTTP_200_OK return token, message
def signin(self, db: Session, request: Request, response: Response, *, obj_in: schema_user.UserPasswordSigninIn): """ 通过密码登录 :param account: 手机号/邮箱/用户名 :param password: 密码 :return: token, 提示信息 """ # -------- 判断输入账号 手机号/邮箱/用户名 ------- # if re.match(RE_PHONE, obj_in.account): # 手机 db_user = crud_user.get_user_by_phone(db, phone=obj_in.account) elif re.match(RE_EMAIL, obj_in.account): # 邮箱 db_user = crud_user.get_user_by_email(db, email=obj_in.account) else: # 用户名 db_user = crud_user.get_user_by_username(db, username=obj_in.account) # --------- 判断账号是否注册过 ---------- # if not db_user: message = f"账号 {obj_in.account} 未注册" response.status_code = status.HTTP_404_NOT_FOUND elif db_user.status == 1: message = f"账号 {obj_in.account} 已被禁用" response.status_code = status.HTTP_403_FORBIDDEN else: # ------ 判断用户是否设置初始密码 ------ # if not db_user.hashed_password: message = f"账号 {obj_in.account} 还未设置初始密码" response.status_code = status.HTTP_401_UNAUTHORIZED return None, message # --------- 密码进行比对 ----------- # if not security.verify_password(obj_in.password, db_user.hashed_password): message = f"用户 {obj_in.account} 密码不正确" response.status_code = status.HTTP_401_UNAUTHORIZED logger.error(message) else: # -------- # 登录token 存储了userid 和 authorityid ------- # access_token_expires = timedelta( minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) token = security.create_access_token( db_user.id, db_user.authorityid, expires_delta=access_token_expires) redis_client.set(db_user.id, token, ex=settings.ACCESS_TOKEN_EXPIRE_MINUTES) # -------- 登录成功之后向数据库添加一条登录日志信息 -------- # ip = request.client.host # 用户ip db_signin_log = crud_user.add_signin_log(db, userid=db_user.id, ip=ip) if not db_signin_log: message = f"用户 {obj_in.account} 登录失败" response.status_code = status.HTTP_401_UNAUTHORIZED else: message = f"用户 {obj_in.account} 登录成功" response.status_code = status.HTTP_200_OK return token, message logger.error(message) return None, message