Beispiel #1
0
    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
Beispiel #2
0
    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
Beispiel #3
0
 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
Beispiel #4
0
    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
Beispiel #5
0
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)
Beispiel #6
0
    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
Beispiel #7
0
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)
Beispiel #8
0
    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
Beispiel #9
0
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
    })
Beispiel #10
0
    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
Beispiel #11
0
    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
Beispiel #12
0
    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