def user(db): """测试普通用户记录 """ user = User(name='test_user', email='*****@*****.**', is_admin=False) user.password = PASSWORD user.save() return user
def test_create_user_success(self, client, admin): """测试创建用户成功 """ # 当前数据库只有 admin 账户 assert User.query.count() == 1 # 用于创建用户的数据 data = { 'name': 'test_user', 'email': '*****@*****.**', 'password': '******' } # 通过 '/users/' 接口创建用户 resp = client.post(url_for(self.endpoint), data=json.dumps(data), headers=self.token_header(admin)) # 创建成功, 返回状态码 201 assert resp.status_code == 201 assert resp.json == {'ok': True} # 成功写入数据库 assert User.query.count() == 2 user = User.query.filter_by(name=data['name']).first() assert user is not None assert user.email == data['email'] # 创建的用户可以进行登录 assert User.authenticate(data['name'], data['password']) == user assert User.authenticate(data['email'], data['password']) == user
def admin(db): """测试管理员用户记录 """ user = User(name='admin', email='*****@*****.**', is_admin=True) user.password = PASSWORD user.save() return user
def wrapper(*args, **kwargs): # 补全代码 print(request.method) if self.admin: if request.method == 'POST': data = request.form else: data = request.args token = request.headers.get('Authorization', '')[4:] or data.get('token', '') User.verify_token(token=token, verify_exp=self.verify_exp) return func(*args, **kwargs)
def post(self): """登录认证用户 用户可以使用昵称或者邮箱进行登录,登录成功后返回用于后续认证的 token """ # FIXME 没有处理 data 为 None 的情况 data = request.get_json() if data is None: raise AuthenticationError(403, 'user name or password required') name = data.get('name') password = data.get('password') if not name or not password: raise AuthenticationError(403, 'user name or password required') # FIXME 只有管理员用户允许登录管理后台 user = User.authenticate(name, password) if not user.is_admin: raise AuthenticationError(403, 'user name or password required') user.login_at = datetime.utcnow() user.save() return {'ok': True, 'token': user.generate_token()}
def post(self): """登录认证用户 用户可以使用昵称或者邮箱进行登录,登录成功后返回用于后续认证的 token """ # FIXME 没有处理 data 为 None 的情况 data = request.get_json() if data is None: raise AuthenticationError(403, 'user name or password required') name = data.get('name') password = data.get('password') if not name or not password: raise AuthenticationError(403, 'user name or password required') # FIXME 只有管理员用户允许登录管理后台 user = User.authenticate(name, password) if not user.is_admin: raise AuthenticationError(403, 'administrator required') user.login_at = datetime.utcnow() user.save() return {'ok': True, 'token': user.generate_token()}
def test_verify_token(self, user): """测试 User.verify_token 类方法 """ # 成功验证 token token = user.generate_token() # 验证 token 成功后会返回 User 对象 u = User.verify_token(token) assert user == u
def test_authenticate(self, user): """测试 User.authenticate 类方法 """ assert User.authenticate(user.name, PASSWORD) assert user.authenticate(user.email, PASSWORD) wrong_password = PASSWORD + '0' try: User.authenticate(user.name, wrong_password) except AuthenticationError as e: assert e.code == 403 assert e.message == 'authentication failed' try: User.authenticate(user.email, wrong_password) except AuthenticationError as e: assert e.code == 403 assert e.message == 'authentication failed'
def wrapper(*args, **kwargs): # 补全代码 jwt_token = request.headers.get('Authorization') if jwt_token is not None: jwt_token = jwt_token.split(" ")[-1] else: jwt_token = request.form.get('token') if jwt_token is None: jwt_token = request.args.get('token') if jwt_token is None: raise RestError(403, 'token not exist') g.instance = User.verify_token(jwt_token) return func(*args, **kwargs)
def init_db(): """初始化数据库 """ db.create_all() print("sqlite3 database file is %s" % app.config['SQLALCHEMY_DATABASE_URI']) # create administrator name, password = User.create_administrator() # 如果 password 为空,代表已经存在 admin 账户 if password != '': print("create admin user %s with password %s" % (name, password))
def handle(self, message): """ 执行相应的命令 """ # 判断命令是否匹配 if not self.check_match(message): return # 判断用户是否已经绑定 user = User.wx_id_user(message.source) if user is not None: return create_reply('你已绑定到 %s 用户' % user.name, message) # 返回绑定用户链接 url = url_for('apps.wx_bind', wx_id=message.source, _external=True) return create_reply('请打开链接 %s 完成用户绑定' % url, message)
def post(self, wx_id): """绑定用户 """ data = request.get_json() if data is None or 'name' not in data or 'password' not in data: return {'ok': False, 'message': '无效用户数据'}, 400 user = User.authenticate(data['name'], data['password']) if user.wx_id is not None: return {'ok': False, 'message': '已绑定到其他微信账户'}, 400 user.wx_id = wx_id user.save() return {'ok': True, 'message': '绑定成功'}
def test_login_success(self, client, admin): """登录成功 """ data = {'name': admin.name, 'password': PASSWORD} resp = client.post(url_for(self.endpoint), data=json.dumps(data), headers={'Content-Type': 'application/json; utf-8'}) assert resp.status_code == 200 assert resp.json['ok'] == True # 获取到的 token 成功验证 u = User.verify_token(resp.json['token']) assert u == admin
def create_app(config=None): """ 创建并初始化 Flask app Args: config(dict): 配置字典 Returns: app (object): Flask App 实例 """ app = Flask('rmon') # 根据环境变量加载开发环境或生产环境配置 env = os.environ.get('RMON_ENV') if env in ('pro', 'prod', 'product'): app.config.from_object(ProductConfig) else: app.config.from_object(DevConfig) # 从环境变量 RMON_SETTINGS 指定的文件中加载配置 app.config.from_envvar('RMON_SETTINGS', silent=True) app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # 从 config 参数更新配置 if config is not None: app.config.update(config) # 注册 Blueprint app.register_blueprint(api) # 初始化数据库 db.init_app(app) # 初始化微信消息处理器 wx_dispatcher.init_app(app) # 如果是开发环境则创建所有数据库表 if app.debug and not app.testing: with app.app_context(): db.create_all() name, password = User.create_administrator() app.logger.debug('create administrator name/password %s/%s', name, password) return app
def handle(self, message): # 判断命令是否匹配 if not self.check_match(message): return # 检查微信用户是否已经绑定到 rmon 用户 user = User.wx_id_user(message.source) if not user: return create_reply('未绑定用户', message) parts = message.content.strip().split(' ') if len(parts) == 1: return create_reply('请输入子命令', message) if parts[1].lower() == 'ls': return create_reply(self.list_servers(), message) elif parts[1].lower() == 'del': return create_reply(self.delete_server(*parts[2:]), message) else: return create_reply('命令暂未实现', message)
def test_generate_token(self, user, app): """测试 User.generate_token 方法 """ now = timegm(datetime.utcnow().utctimetuple()) token = user.generate_token() payload = jwt.decode(token, verify=False) assert payload['uid'] == user.id assert payload['is_admin'] == user.is_admin assert 'refresh_exp' in payload assert 'exp' in payload # 生成的 token 有效期为一天 assert payload['exp'] - now == 24 * 3600 # token 过期后十分钟内,还可以使用老 token 进行刷新 token assert payload['refresh_exp'] - now == 24 * 3600 + 10 * 60 u = User.verify_token(token) assert u == user
def create_app(config): app = Flask("rmon") app.config.from_object(configs.get(config, "development")) # 从环境变量 RMON_SETTINGS 指定的文件中加载配置 app.config.from_envvar('RMON_SETTINGS', silent=True) app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False get_config_from_file(app) register_extensions(app) register_blueprints(app) # 如果是开发环境则创建所有数据库表 if app.debug and not app.testing: with app.app_context(): db.create_all() name, password = User.create_administrator() app.logger.debug('create administrator name/password %s/%s', name, password) return app return app
def test_verify_token_failed(self, user, app): """测试 User.verify_token 验证 token 时失败 """ algorithm = 'HS512' # token 验证失败 invalid_token = user.generate_token() + '0' try: User.verify_token(invalid_token) except InvalidTokenError as e: assert e.code == 403 assert 'Signature' in e.message # token 指定的用户不存在 exp = datetime.utcnow() + timedelta(days=1) # token 过期后十分钟内,还可以使用老 token 进行刷新 token refresh_exp = timegm((exp + timedelta(seconds=60 * 10)).utctimetuple()) # 用户步存在 user_not_exist = 100 payload = { 'uid': user_not_exist, 'is_admin': False, 'exp': exp, 'refresh_exp': refresh_exp } # 用户不存在 try: User.verify_token( jwt.encode(payload, app.secret_key, algorithm=algorithm)) except InvalidTokenError as e: assert e.code == 403 assert e.message == 'user not exist' payload = {'exp': exp} try: User.verify_token( jwt.encode(payload, app.secret_key, algorithm=algorithm)) except InvalidTokenError as e: assert e.code == 403 assert e.message == 'invalid token' # token 刷新时间无效 refresh_exp = datetime.utcnow() - timedelta(days=1)
def wrapper(*args, **kwargs): pack = request.headers.get('Authorization', None) if pack is None: raise AuthenticationError(401, 'token not found') parts = pack.split() # Authorization 头部值必须为 'jwt <token_value>' 这种形式 if parts[0].lower() != 'jwt': raise AuthenticationError(401, 'invalid token header') elif len(parts) == 1: raise AuthenticationError(401, 'token missing') elif len(parts) > 2: raise AuthenticationError(401, 'invalid token') token = parts[1] user = User.verify_token(token, verify_exp=self.verify_exp) # 如果需要验证是否是管理员 if self.admin and not user.is_admin: raise AuthenticationError(403, 'no permission') # 将当前用户存入到 g 对象中 g.user = user return func(*args, **kwargs)