├── .gitignore ├── Dockerfile ├── Pipfile ├── README.md ├── app ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-36.pyc │ └── __init__.cpython-37.pyc ├── api │ ├── __init__.py │ ├── __pycache__ │ │ └── __init__.cpython-37.pyc │ ├── controller │ │ ├── __pycache__ │ │ │ ├── groupController.cpython-37.pyc │ │ │ ├── menuController.cpython-37.pyc │ │ │ ├── parsers.cpython-37.pyc │ │ │ ├── roleController.cpython-37.pyc │ │ │ ├── serializers.cpython-37.pyc │ │ │ └── userController.cpython-37.pyc │ │ ├── groupController.py │ │ ├── menuController.py │ │ ├── parsers.py │ │ ├── roleController.py │ │ ├── serializers.py │ │ └── userController.py │ └── service │ │ ├── __pycache__ │ │ ├── groupService.cpython-37.pyc │ │ ├── menuService.cpython-37.pyc │ │ ├── roleService.cpython-37.pyc │ │ └── userService.cpython-37.pyc │ │ ├── groupService.py │ │ ├── menuService.py │ │ ├── roleService.py │ │ └── userService.py ├── models │ ├── __pycache__ │ │ └── models.cpython-37.pyc │ └── models.py └── site │ ├── __init__.py │ ├── __pycache__ │ ├── __init__.cpython-37.pyc │ └── routes.cpython-37.pyc │ ├── routes.py │ └── templates │ └── layout.html ├── config ├── __pycache__ │ ├── settings.cpython-36.pyc │ └── settings.cpython-37.pyc └── settings.py ├── docker-compose.yml ├── logging.conf ├── rbac.rp ├── requirements.txt ├── runserver.py ├── testDb.sql ├── todo.md └── utils ├── __pycache__ ├── response_code.cpython-37.pyc └── token_auth.cpython-37.pyc ├── response_code.py └── token_auth.py /.gitignore: -------------------------------------------------------------------------------- 1 | /venv 2 | Pipfile.lock 3 | .idea 4 | .DS_Store -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6 2 | 3 | COPY logging.conf runserver.py requirements.txt /api/ 4 | COPY app /api/app 5 | COPY config /api/config 6 | COPY utils /api/utils 7 | 8 | WORKDIR /api 9 | 10 | RUN pip install -r requirements.txt 11 | 12 | EXPOSE 80 13 | 14 | ENTRYPOINT [ "python" ] 15 | 16 | CMD ["runserver.py"] -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | 8 | [packages] 9 | flask = "*" 10 | Flask-SQLAlchemy = "*" 11 | Flask-RESTPlus = "*" 12 | 13 | [requires] 14 | python_version = "3.6" 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 框架 2 | FLASK 3 | SWAGGER 4 | Flask-RESTPlus 5 | 6 | ## 目录 7 | flask-rest-rbac 8 | app 9 | api 10 | controller # api控制层 11 | serializers.py # 封装json参数格式化输出 12 | service # api业务实现层 13 | __init__.py # 设置Flask蓝图,托管API 14 | models # ORM数据库表映射 15 | models.py # sqlacodegen 自动生成 16 | site # Swagger UI 17 | __init__.py # 蓝图API注册,使用API命名空间,组织RESTful资源和HTTP 18 | config # 配置文件 19 | settings.py # Flask配置,数据库配置等 20 | venv # python环境 21 | logging.conf # 日志 22 | Pipfile # 包管理 23 | requirements.txt # 依赖包以及版本号,便于新环境部署 24 | runserver.py # 程序入口启动文件 25 | 26 | 27 | ## 工具 28 | sqlacodegen: 根据已有数据库生成ORM使用的models.py 29 | eg: sqlacodegen 'mysql+pymysql://root:123456@localhost:3306/testDB?charset=utf8' > app/models/models.py 30 | 31 | 32 | ## 技术点 33 | pipenv 34 | flask_restplus: 35 | api.namespace() 创建带有URL前缀的命名空间,description 描述方法 36 | eg: ns_user = Namespace(name='users', description='用户相关操作') 37 | @ns_user.route() 装饰指定网址关联资源 38 | marshal_with()装饰器接受你的数据对象,并对其按照model格式进行字段过滤 39 | Resource: 返回值转换成相应对象 40 | 41 | 嵌套字段: 42 | relationship 43 | ForeignKey 44 | 45 | 批量操作: 46 | db.session.flush() 47 | 模型继承: 48 | menuElementOperation = api.inherit('Model menuElementOperation', menu, { 49 | 'elements': fields.List(fields.Nested(menuElement)), 50 | 'operations': fields.List(fields.Nested(menuOperation)) 51 | }) 52 | 分页paginate: 53 | paginate(page = None,per_page = None,error_out = True,max_per_page = None ) 54 | per_page从页面返回项目page。 55 | 56 | 如果page或者per_page是None,他们将请求查询检索。如果max_per_page指定,per_page则将限制为该值。如果没有请求或它们不在查询中,则它们分别默认为1和20。 57 | 58 | 如果error_out是True(默认),以下规则将导致404响应: 59 | 60 | 没有找到任何物品,page也不是1。 61 | 62 | page小于1,或者per_page是负数。 63 | 64 | page或者per_page不是整数。 65 | 66 | 当error_out是False,page并且per_page默认为分别为1和20。 67 | token认证: 68 | 见参考文献flask之token认证, 69 | RESTFul扩展集成,decorators = [auth.login_required] 70 | response: 71 | jsonify直接返回的是Content-type:application/json的响应对象(Response对象) 72 | json.dumps返回的,则是Content-type:text/html,charset=utf-8的HTML格式 73 | 74 | ## log 75 | 2019-08-14 添加.gitignore,删除多余文件 76 | 修正DB.sql 77 | 添加docker打包(启动命令:docker-compose up) 78 | 79 | ## 参考文献 80 | 81 | [Flask 快速入门](http://docs.jinkan.org/docs/flask/quickstart.html# "悬停") 82 | 83 | [Flask,Swagger UI 和 Flask-RESTlus构建REST API](http://michal.karzynski.pl/blog/2016/06/19/building-beautiful-restful-apis-using-flask-swagger-ui-flask-restplus/) 84 | 85 | [FlaskRESTful](http://www.pythondoc.com/Flask-RESTful/index.html) 86 | 87 | [Flask-SQLAlchemy](http://www.pythondoc.com/flask-sqlalchemy/index.html) 88 | 89 | [flask之token认证](https://blog.csdn.net/ousuixin/article/details/94053454) -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Author : Guohao 4 | # @Time : 2019-07-19 13:06 5 | 6 | # Create a Flask WSGI application 7 | from flask import Flask 8 | from flask_sqlalchemy import SQLAlchemy 9 | from flask_cors import CORS 10 | from flask_httpauth import HTTPTokenAuth 11 | 12 | app = Flask(__name__) 13 | # 读取配置 14 | app.config.from_object('config.settings') 15 | 16 | # flask的跨域解决 17 | CORS(app) 18 | 19 | # 数据库初始化 20 | db = SQLAlchemy(app) 21 | # 验证的初始化 22 | auth = HTTPTokenAuth(scheme='Bearer') 23 | 24 | 25 | from app.api import api, api_blueprint 26 | from app.api.controller.userController import ns_user 27 | from app.api.controller.roleController import ns_role 28 | from app.api.controller.groupController import ns_group 29 | from app.api.controller.menuController import ns_menu 30 | 31 | api.add_namespace(ns_user) 32 | api.add_namespace(ns_role) 33 | api.add_namespace(ns_group) 34 | api.add_namespace(ns_menu) 35 | app.register_blueprint(blueprint=api_blueprint) 36 | 37 | from app.site.routes import site_blueprint 38 | app.register_blueprint(blueprint=site_blueprint) 39 | 40 | db.create_all() -------------------------------------------------------------------------------- /app/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/app/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /app/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/app/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /app/api/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Author : Guohao 4 | # @Time : 2019-07-19 13:47 5 | 6 | import logging 7 | import traceback 8 | 9 | from flask import Blueprint 10 | from flask_restplus import Api 11 | from sqlalchemy.orm.exc import NoResultFound 12 | 13 | import config.settings 14 | 15 | log = logging.getLogger(__name__) 16 | 17 | api_blueprint = Blueprint('api', __name__, url_prefix='/api') 18 | 19 | api = Api( 20 | app=api_blueprint, 21 | version='1.0.0', 22 | title='Swagger', 23 | description='''Flask,Blueprint, Flask-Restplus and Swagger Api example, 24 | 参考文案:http://michal.karzynski.pl/blog/2016/06/19/building-beautiful-restful-apis-using-flask-swagger-ui-flask-restplus/ 25 | ''', 26 | contact='guohao', 27 | contact_url='', 28 | contact_email='511721582@qq.com', 29 | ) 30 | 31 | # @api.errorhandler装饰器覆盖默认错误处理程序 32 | @api.errorhandler 33 | def default_error_handler(e): 34 | message = 'An unhandled exception occurred.' 35 | log.exception(message) 36 | 37 | if not config.settings.FLASK_DEBUG: 38 | return {'message': message}, 500 39 | 40 | 41 | @api.errorhandler(NoResultFound) 42 | def database_not_found_error_handler(e): 43 | log.warning(traceback.format_exc()) 44 | return {'message': '未找到该数据.'}, 404 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /app/api/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/app/api/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /app/api/controller/__pycache__/groupController.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/app/api/controller/__pycache__/groupController.cpython-37.pyc -------------------------------------------------------------------------------- /app/api/controller/__pycache__/menuController.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/app/api/controller/__pycache__/menuController.cpython-37.pyc -------------------------------------------------------------------------------- /app/api/controller/__pycache__/parsers.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/app/api/controller/__pycache__/parsers.cpython-37.pyc -------------------------------------------------------------------------------- /app/api/controller/__pycache__/roleController.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/app/api/controller/__pycache__/roleController.cpython-37.pyc -------------------------------------------------------------------------------- /app/api/controller/__pycache__/serializers.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/app/api/controller/__pycache__/serializers.cpython-37.pyc -------------------------------------------------------------------------------- /app/api/controller/__pycache__/userController.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/app/api/controller/__pycache__/userController.cpython-37.pyc -------------------------------------------------------------------------------- /app/api/controller/groupController.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Author : Guohao 4 | # @Time : 2019-07-20 08:41 5 | 6 | import logging 7 | from flask import request 8 | from flask_restplus import Namespace, Resource 9 | from app.models.models import Group 10 | from app.api.controller.serializers import group, groupBindRole 11 | from app.api.service.groupService import create_group, update_group, delete_group, bind_role 12 | 13 | log = logging.getLogger(__name__) 14 | ns_group = Namespace(name='groups', description='用户组相关操作') 15 | 16 | @ns_group.route('/getGroupList') 17 | class GetGroupList(Resource): 18 | @ns_group.marshal_list_with(group) 19 | def get(self): 20 | """ 21 | 返回用户组列表 22 | """ 23 | groups = Group.query.all() 24 | return groups 25 | 26 | @ns_group.route('/createGroup') 27 | class CreateGroup(Resource): 28 | @ns_group.response(201, '创建用户组成功') 29 | @ns_group.expect(group) 30 | def post(self): 31 | """ 32 | 创建用户组 33 | """ 34 | data = request.json 35 | create_group(data) 36 | return None, 201 37 | 38 | 39 | @ns_group.route('/updateGroup/') 40 | class UpdateGroup(Resource): 41 | @ns_group.response(204, '修改用户成功') 42 | @ns_group.expect(group) 43 | def put(self, id): 44 | """ 45 | 修改用户组 46 | """ 47 | data = request.json 48 | update_group(id, data) 49 | return None, 204 50 | 51 | @ns_group.route('/deleteGroup/') 52 | class DeleteGroup(Resource): 53 | def delete(self, id): 54 | """ 55 | 删除用户组 56 | """ 57 | delete_group(id) 58 | return None, 204 59 | 60 | @ns_group.route('/bindRole') 61 | class BindRole(Resource): 62 | @ns_group.response(204, '绑定用户角色') 63 | @ns_group.expect(groupBindRole) 64 | def post(self): 65 | """ 66 | 用户组绑定角色 67 | :return: 68 | """ 69 | data = request.json 70 | bind_role(data) 71 | return None, 204 -------------------------------------------------------------------------------- /app/api/controller/menuController.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Author : Guohao 4 | # @Time : 2019-07-20 09:17 5 | 6 | import logging 7 | from flask import request 8 | from flask_restplus import Namespace, Resource 9 | from app.models.models import Menu 10 | from app.api.controller.serializers import menu, menuElementOperation 11 | from app.api.service.menuService import creata_menu, update_menu, delete_menu, getMenuElementOperation 12 | 13 | log = logging.getLogger(__name__) 14 | ns_menu = Namespace(name='menus', description='菜单相关操作') 15 | 16 | @ns_menu.route('/getMenuElementOperationList') 17 | class GetMenuList(Resource): 18 | @ns_menu.marshal_list_with(menuElementOperation) 19 | def get(self): 20 | """ 21 | 返回菜单及菜单元素和菜单操作列表 22 | """ 23 | menuElementOperation = getMenuElementOperation() 24 | return menuElementOperation 25 | 26 | 27 | @ns_menu.route('/getMenuList') 28 | class GetMenuList(Resource): 29 | @ns_menu.marshal_list_with(menu) 30 | def get(self): 31 | """ 32 | 返回菜单列表 33 | """ 34 | menus = Menu.query.all() 35 | return menus 36 | 37 | @ns_menu.route('/createMenu') 38 | class CreateMenu(Resource): 39 | @ns_menu.response(201, '创建菜单成功') 40 | @ns_menu.expect(menuElementOperation) 41 | def post(self): 42 | """ 43 | 创建菜单 44 | """ 45 | data = request.json 46 | creata_menu(data) 47 | return None, 201 48 | 49 | 50 | @ns_menu.route('/updateMenu/') 51 | class UpdateMenu(Resource): 52 | @ns_menu.response(204, '修改菜单成功') 53 | @ns_menu.expect(menuElementOperation) 54 | def put(self, id): 55 | """ 56 | 修改菜单 57 | """ 58 | data = request.json 59 | update_menu(id, data) 60 | return None, 204 61 | 62 | @ns_menu.route('/deleteMenu/') 63 | class DeleteMenu(Resource): 64 | def delete(self, id): 65 | """ 66 | 删除菜单 67 | """ 68 | delete_menu(id) 69 | return None, 204 -------------------------------------------------------------------------------- /app/api/controller/parsers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Author : Guohao 4 | # @Time : 2019-07-23 20:23 5 | 6 | from flask_restplus import reqparse 7 | 8 | pagination_arguments = reqparse.RequestParser() 9 | pagination_arguments.add_argument('page', type=int, required=False, default=1, help='Page number') 10 | pagination_arguments.add_argument('bool', type=bool, required=False, default=True, help='Page number') 11 | pagination_arguments.add_argument('per_page', type=int, required=False, choices=[2, 10, 20, 30, 40, 50], 12 | default=20, help='Results per page') 13 | -------------------------------------------------------------------------------- /app/api/controller/roleController.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Author : Guohao 4 | # @Time : 2019-07-19 17:24 5 | 6 | import logging 7 | from flask import request 8 | from flask_restplus import Namespace, Resource 9 | from app.models.models import Role 10 | from app.api.controller.serializers import role 11 | from app.api.service.roleService import creata_role, update_role, delete_role 12 | 13 | log = logging.getLogger(__name__) 14 | ns_role = Namespace(name='roles', description='角色相关操作') 15 | 16 | @ns_role.route('/getRoleList') 17 | class GetRoleList(Resource): 18 | @ns_role.marshal_list_with(role) 19 | def get(self): 20 | """ 21 | 返回角色列表 22 | """ 23 | roles = Role.query.all() 24 | return roles 25 | 26 | @ns_role.route('/createRole') 27 | class CreateRole(Resource): 28 | @ns_role.response(201, '创建角色成功') 29 | @ns_role.expect(role) 30 | def post(self): 31 | """ 32 | 创建角色 33 | """ 34 | data = request.json 35 | creata_role(data) 36 | return None, 201 37 | 38 | 39 | @ns_role.route('/updateRole/') 40 | class UpdateRole(Resource): 41 | @ns_role.response(204, '修改用户成功') 42 | @ns_role.expect(role) 43 | def put(self, id): 44 | """ 45 | 修改角色 46 | """ 47 | data = request.json 48 | update_role(id, data) 49 | return None, 204 50 | 51 | @ns_role.route('/deleteRole/') 52 | class DeleteRole(Resource): 53 | def delete(self, id): 54 | """ 55 | 删除角色 56 | """ 57 | delete_role(id) 58 | return None, 204 -------------------------------------------------------------------------------- /app/api/controller/serializers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Author : Guohao 4 | # @Time : 2019-07-19 14:46 5 | 6 | # 接口输入输出 7 | from flask_restplus import fields 8 | from app.api import api 9 | 10 | user = api.model('Model User', { 11 | 'id': fields.String(readOnly=False, description='用户id'), 12 | 'username': fields.String(required=False, description='用户名'), 13 | 'nickname': fields.String(required=False, description='昵称'), 14 | 'password': fields.String(required=False, description='密码'), 15 | 'phone': fields.String(required=False, description='手机号码'), 16 | 'email': fields.String(required=False, description=''), 17 | 'is_children': fields.Integer(required=False, description=''), 18 | 'parent_id': fields.String(required=False, description=''), 19 | 'status': fields.String(required=False, description=''), 20 | 'founder': fields.String(required=False, description=''), 21 | 'founder_name': fields.String(required=False, description=''), 22 | 'foundtime': fields.DateTime(required=False, description=''), 23 | 'updater': fields.String(required=False, description=''), 24 | 'updater_name': fields.String(required=False, description=''), 25 | 'updatetime': fields.DateTime(required=False, description='') 26 | }) 27 | 28 | pagination = api.model('A page of results', { 29 | 'page': fields.Integer(description='Number of this page of results'), 30 | 'pages': fields.Integer(description='Total number of pages of results'), 31 | 'per_page': fields.Integer(description='Number of items per page of results'), 32 | 'total': fields.Integer(description='Total number of results'), 33 | }) 34 | 35 | page_of_users = api.inherit('Page of user', pagination, { 36 | 'items': fields.List(fields.Nested(user)) 37 | }) 38 | 39 | role = api.model('Model Role', { 40 | 'id': fields.String(), 41 | 'role_name': fields.String(), 42 | 'role_desc': fields.String(), 43 | 'status': fields.String(), 44 | 'founder': fields.String(), 45 | 'founder_name': fields.String(), 46 | 'foundtime': fields.DateTime(), 47 | 'updater': fields.String(), 48 | 'updater_name': fields.String(), 49 | 'updatetime': fields.DateTime() 50 | }) 51 | 52 | userBindRole = api.model('Model userBindRole', { 53 | 'user_id': fields.String(), 54 | 'role_ids': fields.List(fields.String) 55 | }) 56 | 57 | group = api.model('Model Group', { 58 | 'id': fields.String(), 59 | 'groupname': fields.String(), 60 | 'parent_id': fields.String(), 61 | 'parent_name': fields.String(), 62 | 'status': fields.String(), 63 | 'founder': fields.String(), 64 | 'founder_name': fields.String(), 65 | 'foundtime': fields.DateTime(), 66 | 'updater': fields.String(), 67 | 'updater_name': fields.String(), 68 | 'updatetime': fields.DateTime() 69 | }) 70 | 71 | groupBindRole = api.model('Model groupBindRole', { 72 | 'group_id': fields.String(), 73 | 'role_ids': fields.List(fields.String) 74 | }) 75 | 76 | menu = api.model('Model Menu', { 77 | 'id': fields.String(), 78 | 'menu_code': fields.String(), 79 | 'menu_name': fields.String(), 80 | 'menu_icon': fields.String(), 81 | 'menu_path': fields.String(), 82 | 'parent_id': fields.String(), 83 | 'sort': fields.Integer(), 84 | 'is_hidden': fields.Integer(), 85 | 'status': fields.String(), 86 | 'state': fields.Integer(), 87 | 'founder': fields.String(), 88 | 'founder_name': fields.String(), 89 | 'foundtime': fields.DateTime(), 90 | 'updater': fields.String(), 91 | 'updater_name': fields.String(), 92 | 'updatetime': fields.DateTime() 93 | }) 94 | 95 | menuElement = api.model('Model menuElement', { 96 | 'id': fields.String(), 97 | 'element_code': fields.String(), 98 | 'element_name': fields.String() 99 | }) 100 | menuOperation = api.model('Model menuOperation', { 101 | 'id': fields.String(), 102 | 'operation_code': fields.String(), 103 | 'operation_name': fields.String() 104 | }) 105 | 106 | # 模型继承 107 | menuElementOperation = api.inherit('Model menuElementOperation', menu, { 108 | 'elements': fields.List(fields.Nested(menuElement)), 109 | 'operations': fields.List(fields.Nested(menuOperation)) 110 | }) -------------------------------------------------------------------------------- /app/api/controller/userController.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Author : Guohao 4 | # @Time : 2019-07-19 13:51 5 | 6 | import logging 7 | from flask import request, abort, Response, jsonify, g 8 | from flask_restplus import Namespace, Resource, fields 9 | from app.api import api 10 | 11 | from app.models.models import User 12 | from app.api.controller.serializers import user, userBindRole, page_of_users 13 | from app.api.controller.parsers import pagination_arguments 14 | from app.api.service.userService import creata_user, update_user, delete_user, bind_role 15 | from utils.token_auth import auth, verify_token 16 | from utils.response_code import Ret 17 | 18 | log = logging.getLogger(__name__) 19 | # 定义命名空间 20 | ns_user = Namespace(name='users', description='用户相关操作') 21 | 22 | @ns_user.route('/checkToken') 23 | class checkToken(Resource): 24 | def get(self): 25 | """ 26 | 校验token是否有效 27 | :return: 28 | """ 29 | data = request.headers.get('Token') 30 | bToken = verify_token(data) 31 | if bToken: 32 | return jsonify(code=Ret.SUCCESS, msg='token 有效') 33 | else: 34 | return jsonify(code=Ret.FAILURE, msg='token 无效') 35 | 36 | 37 | @ns_user.route('/login') 38 | class login(Resource): 39 | # 请求参数 40 | login = api.model('Login', { 41 | 'username': fields.String(required=True, description='用户名'), 42 | 'password': fields.String(required=True, description='密码') 43 | }) 44 | @ns_user.expect(login) 45 | def post(self): 46 | """ 47 | 登录,获取用户信息以及生成token 48 | :return: 49 | """ 50 | data = request.json 51 | username = data.get('username') 52 | password = data.get('password') 53 | user = User.query.filter(User.username == username).first() 54 | if User.verify_password(user, password): 55 | # 生成token 56 | token = user.generate_auth_token() 57 | return jsonify(code=Ret.SUCCESS, msg="登录成功", data={'token': token.decode('utf-8'), 'name': user.username}) 58 | else: 59 | return jsonify(code=Ret.FAILURE, msg="密码错误") 60 | 61 | @ns_user.route('/logout') 62 | class logout(Resource): 63 | @auth.login_required 64 | def logout(self): 65 | return jsonify(Ret.SUCCESS, msg="退出成功") 66 | 67 | 68 | @ns_user.route('/getUserList') 69 | class GetUserList(Resource): 70 | # RESTFul 扩展集成 decorators,注入视图装饰器 71 | # decorators = [auth.login_required] 72 | # @ns_user.marshal_list_with(user) 73 | @auth.login_required 74 | def get(self): 75 | """ 76 | 返回用户列表. 77 | """ 78 | users = User.query.all() 79 | user_list = [] 80 | for user in users: 81 | user_list.append(user.to_dict()) 82 | 83 | data = user_list 84 | return jsonify(code=Ret.SUCCESS, msg="查询成功", data=data) 85 | 86 | @ns_user.route('/getUserListForPage') 87 | class GetUserListForPage(Resource): 88 | @ns_user.expect(pagination_arguments) 89 | # @ns_user.marshal_with(page_of_users) 90 | def get(self): 91 | """ 92 | 分页返回用户列表. 93 | """ 94 | args = pagination_arguments.parse_args(request) 95 | page = args.get('page', 1) 96 | per_page = args.get('per_page', 2) 97 | print(per_page, 'per_page') 98 | 99 | users_query = User.query 100 | users_page = users_query.filter(User.founder == g.user.id).paginate(page, per_page, error_out=False) 101 | user_list = [] 102 | for user in users_page.items: 103 | user_list.append(user.to_dict()) 104 | 105 | data = { 106 | 'users': user_list, 107 | 'total': users_page.total, 108 | 'pages': users_page.pages, 109 | 'page': users_page.page 110 | } 111 | return jsonify(code=Ret.SUCCESS, msg="查询成功", data=data) 112 | 113 | @ns_user.route('/createUser') 114 | class CretaUser(Resource): 115 | # @ns_user.response(201, '创建用户成功') 116 | # @ns_user.expect(user) 117 | user = api.model('Model User', { 118 | 'username': fields.String(required=True, description='用户名'), 119 | 'nickname': fields.String(required=False, description='昵称'), 120 | 'password': fields.String(required=True, description='密码'), 121 | 'phone': fields.String(required=False, description='手机号码'), 122 | 'email': fields.String(required=False, description=''), 123 | 'is_children': fields.Integer(required=False, description=''), 124 | 'parent_id': fields.String(required=False, description='') 125 | }) 126 | 127 | @ns_user.expect(user) 128 | @auth.login_required 129 | def post(self): 130 | """ 131 | 创建用户 132 | """ 133 | data = request.json 134 | if data.get('password') == '' or data.get('password') is None: 135 | # abort() 立即停止视图函数的执行,并且把相对应的信息返回到前端中 136 | # abort(Response("密码不能为空")) 137 | return jsonify(code=Ret.FAILURE, msg="密码不能为空") 138 | creata_user(data) 139 | 140 | # return None, 201 141 | return jsonify(code=Ret.SUCCESS, msg="创建成功") 142 | 143 | @ns_user.route('/updateUser/') 144 | class UpdateUser(Resource): 145 | @ns_user.response(204, '修改用户成功') 146 | @ns_user.expect(user) 147 | def put(self, id): 148 | """ 149 | 修改用户 150 | """ 151 | data = request.json 152 | update_user(id, data) 153 | return None, 204 154 | 155 | @ns_user.route('/deleteUser/') 156 | class DeleteUser(Resource): 157 | def delete(self, id): 158 | """ 159 | 删除用户 160 | """ 161 | delete_user(id) 162 | return None, 204 163 | 164 | @ns_user.route('/bindRole') 165 | class BindRole(Resource): 166 | @ns_user.response(204, '绑定用户角色') 167 | @ns_user.expect(userBindRole) 168 | def post(self): 169 | """ 170 | 用户绑定角色 171 | :return: 172 | """ 173 | data = request.json 174 | bind_role(data) 175 | return None, 204 -------------------------------------------------------------------------------- /app/api/service/__pycache__/groupService.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/app/api/service/__pycache__/groupService.cpython-37.pyc -------------------------------------------------------------------------------- /app/api/service/__pycache__/menuService.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/app/api/service/__pycache__/menuService.cpython-37.pyc -------------------------------------------------------------------------------- /app/api/service/__pycache__/roleService.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/app/api/service/__pycache__/roleService.cpython-37.pyc -------------------------------------------------------------------------------- /app/api/service/__pycache__/userService.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/app/api/service/__pycache__/userService.cpython-37.pyc -------------------------------------------------------------------------------- /app/api/service/groupService.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Author : Guohao 4 | # @Time : 2019-07-20 08:44 5 | 6 | 7 | from app import db 8 | from app.models.models import Group, GroupRole 9 | import uuid, time 10 | 11 | def create_group(data): 12 | group = Group() 13 | 14 | group.id = str(uuid.uuid1()) 15 | group.groupname = data.get('groupname') 16 | group.parent_id = data.get('parent_id') 17 | group.parent_name = data.get('parent_name') 18 | group.status = data.get('status') 19 | group.foundtime = time.strftime('%Y-%m-%d %H:%M:%S') 20 | 21 | db.session.add(group) 22 | db.session.commit() 23 | 24 | def update_group(id, data): 25 | group = Group.query.filter(Group.id == id).one() 26 | group.groupname = data.get('groupname') 27 | group.parent_id = data.get('parent_id') 28 | group.parent_name = data.get('parent_name') 29 | group.status = data.get('status') 30 | group.updatetime = time.strftime('%Y-%m-%d %H:%M:%S') 31 | 32 | db.session.add(group) 33 | db.session.commit() 34 | 35 | def delete_group(id): 36 | group = Group.query.filter(Group.id == id).one() 37 | db.session.delete(group) 38 | db.session.commit() 39 | 40 | def bind_role(data): 41 | group_id = data.get('group_id') 42 | role_ids = data.get('role_ids') 43 | for role_id in role_ids: 44 | groupRole = GroupRole() 45 | groupRole.group_id = group_id 46 | # 已存在,跳过 47 | sameGroupRoleCount = GroupRole.query.filter(GroupRole.group_id == group_id, GroupRole.role_id == role_id).count() 48 | if sameGroupRoleCount > 0: 49 | continue 50 | groupRole.status = '1' 51 | groupRole.foundtime = time.strftime('%Y-%m-%d %H:%M:%S') 52 | id = str(uuid.uuid1()) 53 | groupRole.id = id 54 | groupRole.role_id = role_id 55 | db.session.add(groupRole) 56 | db.session.flush() 57 | db.session.commit() -------------------------------------------------------------------------------- /app/api/service/menuService.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Author : Guohao 4 | # @Time : 2019-07-21 21:32 5 | 6 | from app import db 7 | from app.models.models import Menu, MenuElement, MenuOperation 8 | import uuid, time 9 | 10 | def creata_menu(data): 11 | menu = Menu() 12 | 13 | menu.id = str(uuid.uuid1()) 14 | menu.menu_code = data.get('menu_code') 15 | menu.menu_name = data.get('menu_name') 16 | menu.menu_icon = data.get('menu_icon') 17 | menu.menu_path = data.get('menu_path') 18 | menu.parent_id = data.get('parent_id') 19 | menu.sort = data.get('sort') 20 | menu.is_hidden = data.get('is_hidden') 21 | menu.status = data.get('status') 22 | menu.foundtime = time.strftime('%Y-%m-%d %H:%M:%S') 23 | elements = data.get('elements') 24 | operations = data.get('operations') 25 | for element in elements: 26 | menuElement = MenuElement() 27 | menuElement.id = str(uuid.uuid1()) 28 | menuElement.menu_id = menu.id 29 | menuElement.element_code = element.get('element_code') 30 | menuElement.element_name = element.get('element_name') 31 | menuElement.foundtime = time.strftime('%Y-%m-%d %H:%M:%S') 32 | db.session.add(menuElement) 33 | db.session.flush() 34 | for operation in operations: 35 | menuOperation = MenuOperation() 36 | menuOperation.id = str(uuid.uuid1()) 37 | menuOperation.menu_id = menu.id 38 | menuOperation.operation_code = operation.get('operation_code') 39 | menuOperation.operation_name = operation.get('operation_name') 40 | menuOperation.foundtime = time.strftime('%Y-%m-%d %H:%M:%S') 41 | db.session.add(menuOperation) 42 | db.session.flush() 43 | db.session.add(menu) 44 | db.session.commit() 45 | 46 | def update_menu(id, data): 47 | menu = Menu.query.filter(Menu.id == id).one() 48 | menu.menu_code = data.get('menu_code') 49 | menu.menu_name = data.get('menu_name') 50 | menu.menu_icon = data.get('menu_icon') 51 | menu.menu_path = data.get('menu_path') 52 | menu.parent_id = data.get('parent_id') 53 | menu.sort = data.get('sort') 54 | menu.is_hidden = data.get('is_hidden') 55 | menu.status = data.get('status') 56 | menu.updatetime = time.strftime('%Y-%m-%d %H:%M:%S') 57 | elements = data.get('elements') 58 | operations = data.get('operations') 59 | for element in elements: 60 | menuElement = MenuElement() 61 | menuElement.id = element.get('id') 62 | menuElement.menu_id = menu.id 63 | menuElement.element_code = element.get('element_code') 64 | menuElement.element_name = element.get('element_name') 65 | menuElement.foundtime = time.strftime('%Y-%m-%d %H:%M:%S') 66 | db.session.add(menuElement) 67 | db.session.flush() 68 | for operation in operations: 69 | menuOperation = MenuOperation() 70 | menuOperation.id = element.get('id') 71 | menuOperation.menu_id = menu.id 72 | menuOperation.operation_code = operation.get('operation_code') 73 | menuOperation.operation_name = operation.get('operation_name') 74 | menuOperation.foundtime = time.strftime('%Y-%m-%d %H:%M:%S') 75 | db.session.add(menuOperation) 76 | db.session.flush() 77 | 78 | db.session.add(menu) 79 | db.session.commit() 80 | 81 | def delete_menu(id): 82 | menu = Menu.query.filter(Menu.id == id).one() 83 | menuElements = MenuElement.query.filter(MenuElement.menu_id == id).all() 84 | for menuElement in menuElements: 85 | db.session.delete(menuElement) 86 | db.session.flush() 87 | menuOperations = MenuOperation.query.filter(MenuOperation.menu_id == id).all() 88 | for menuOperation in menuOperations: 89 | db.session.delete(menuOperation) 90 | db.session.flush() 91 | db.session.delete(menu) 92 | db.session.commit() 93 | 94 | def getMenuElementOperation(): 95 | query = db.session().query(Menu) 96 | # outerjoin 左连接 97 | query = query.outerjoin(MenuElement, MenuElement.menu_id == Menu.id).outerjoin(MenuOperation, MenuOperation.menu_id == Menu.id) 98 | data = query.all() 99 | return data 100 | -------------------------------------------------------------------------------- /app/api/service/roleService.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Author : Guohao 4 | # @Time : 2019-07-19 17:32 5 | 6 | from app import db 7 | from app.models.models import Role 8 | import uuid, time 9 | 10 | def creata_role(data): 11 | role_name = data.get('role_name') 12 | 13 | role = Role(role_name) 14 | 15 | role.id = str(uuid.uuid1()) 16 | role.role_desc = data.get('role_desc') 17 | role.status = data.get('status') 18 | 19 | role.foundtime = time.strftime('%Y-%m-%d %H:%M:%S') 20 | 21 | db.session.add(role) 22 | db.session.commit() 23 | 24 | def update_role(id, data): 25 | role = Role.query.filter(Role.id == id).one() 26 | role.role_name = data.get('role_name') 27 | role.role_desc = data.get('role_desc') 28 | role.status = data.get('status') 29 | role.updatetime = time.strftime('%Y-%m-%d %H:%M:%S') 30 | 31 | db.session.add(role) 32 | db.session.commit() 33 | 34 | def delete_role(id): 35 | role = Role.query.filter(Role.id == id).one() 36 | db.session.delete(role) 37 | db.session.commit() -------------------------------------------------------------------------------- /app/api/service/userService.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Author : Guohao 4 | # @Time : 2019-07-19 15:25 5 | 6 | from flask import g 7 | from app import db 8 | from app.models.models import User 9 | from app.models.models import UserRole 10 | import uuid, time 11 | 12 | def creata_user(data): 13 | phone = data.get('phone') 14 | 15 | user = User() 16 | user.id = str(uuid.uuid1()) 17 | user.username = data.get('username') 18 | user.nickname = data.get('nickname') 19 | user.password = user.hash_password(data.get('password')) 20 | user.phone = str(phone) 21 | if g.user and g.user.id and g.user.username: 22 | user.founder = g.user.id 23 | user.founder_name = g.user.username 24 | user.foundtime = time.strftime('%Y-%m-%d %H:%M:%S') 25 | 26 | db.session.add(user) 27 | db.session.commit() 28 | 29 | def update_user(id, data): 30 | user = User.query.filter(User.id == id).one() 31 | # one() 仅返回一个查询结果,结果数量不足一个或多余一个时报错 32 | user.username = data.get('username') 33 | user.nickname = data.get('nickname') 34 | user.password = data.get('password') 35 | user.phone = data.get('phone') 36 | user.updatetime = time.strftime('%Y-%m-%d %H:%M:%S') 37 | 38 | db.session.add(user) 39 | db.session.commit() 40 | 41 | def delete_user(id): 42 | user = User.query.filter(User.id == id).one() 43 | # one() 仅返回一个查询结果,结果数量不足一个或多余一个时报错 44 | db.session.delete(user) 45 | db.session.commit() 46 | 47 | def bind_role(data): 48 | user_id = data.get('user_id') 49 | role_ids = data.get('role_ids') 50 | for role_id in role_ids: 51 | userRole = UserRole() 52 | userRole.user_id = user_id 53 | # 已存在,跳过 54 | sameUserRoleCount = UserRole.query.filter(UserRole.user_id == user_id, UserRole.role_id == role_id).count() 55 | if sameUserRoleCount > 0: 56 | continue 57 | userRole.status = '1' 58 | userRole.foundtime = time.strftime('%Y-%m-%d %H:%M:%S') 59 | id = str(uuid.uuid1()) 60 | userRole.id = id 61 | userRole.role_id = role_id 62 | db.session.add(userRole) 63 | db.session.flush() 64 | db.session.commit() -------------------------------------------------------------------------------- /app/models/__pycache__/models.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/app/models/__pycache__/models.cpython-37.pyc -------------------------------------------------------------------------------- /app/models/models.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # sqlacodegen 'mysql+pymysql://root:123456@localhost:3306/testDB?charset=utf8' > app/models/models.py 3 | from sqlalchemy import Column, DateTime, String, text 4 | from sqlalchemy.dialects.mysql import INTEGER, TINYINT 5 | # 加密解密密码的库 6 | from passlib.apps import custom_app_context 7 | import config.settings 8 | # URL安全序列化工具 9 | from itsdangerous import (TimedJSONWebSignatureSerializer 10 | as Serializer, BadSignature, SignatureExpired) 11 | # from sqlalchemy.ext.declarative import declarative_db.Model 12 | # 13 | # Base = declarative_db.Model() 14 | # metadata = Base.metadata 15 | from app import db 16 | 17 | class Group(db.Model): 18 | __tablename__ = 'group' 19 | 20 | id = Column(String(128), primary_key=True) 21 | groupname = Column(String(128)) 22 | parent_id = Column(String(128)) 23 | parent_name = Column(String(128)) 24 | status = Column(String(32)) 25 | founder = Column(String(128)) 26 | founder_name = Column(String(128)) 27 | foundtime = Column(DateTime) 28 | updater = Column(String(128)) 29 | updater_name = Column(String(128)) 30 | updatetime = Column(DateTime) 31 | 32 | def __init__(self): 33 | self 34 | 35 | 36 | class GroupRole(db.Model): 37 | __tablename__ = 'group_role' 38 | 39 | id = Column(String(128), primary_key=True) 40 | group_id = Column(String(128)) 41 | role_id = Column(String(128)) 42 | status = Column(String(32)) 43 | founder = Column(String(128)) 44 | founder_name = Column(String(128)) 45 | foundtime = Column(DateTime) 46 | updater = Column(String(128)) 47 | updater_name = Column(String(128)) 48 | updatetime = Column(DateTime) 49 | 50 | def __init__(self): 51 | self 52 | 53 | 54 | class Menu(db.Model): 55 | __tablename__ = 'menu' 56 | 57 | id = Column(String(128), primary_key=True) 58 | menu_code = Column(String(64), unique=True) 59 | menu_name = Column(String(128)) 60 | menu_icon = Column(String(128)) 61 | menu_path = Column(String(128)) 62 | parent_id = Column(String(128)) 63 | sort = Column(INTEGER(11)) 64 | is_hidden = Column(TINYINT(4), server_default=text("'0'")) 65 | status = Column(String(32)) 66 | state = Column(TINYINT(4)) 67 | founder = Column(String(128)) 68 | founder_name = Column(String(128)) 69 | foundtime = Column(DateTime) 70 | updater = Column(String(128)) 71 | updater_name = Column(String(128)) 72 | updatetime = Column(DateTime) 73 | elements = db.relationship('MenuElement', backref='', lazy='dynamic') 74 | operations = db.relationship('MenuOperation', backref='', lazy='dynamic') 75 | 76 | def __init__(self): 77 | self 78 | 79 | class MenuElement(db.Model): 80 | __tablename__ = 'menu_element' 81 | 82 | id = Column(String(128), primary_key=True) 83 | element_code = Column(String(128)) 84 | element_name = Column(String(128)) 85 | menu_id = Column(String(128), db.ForeignKey(Menu.id)) 86 | state = Column(TINYINT(4)) 87 | founder = Column(String(128)) 88 | founder_name = Column(String(128)) 89 | foundtime = Column(DateTime) 90 | updater = Column(String(128)) 91 | updater_name = Column(String(128)) 92 | updatetime = Column(DateTime) 93 | 94 | def __init__(self): 95 | self 96 | 97 | 98 | class MenuOperation(db.Model): 99 | __tablename__ = 'menu_operation' 100 | 101 | id = Column(String(128), primary_key=True) 102 | operation_code = Column(String(128)) 103 | operation_name = Column(String(128)) 104 | menu_id = Column(String(128), db.ForeignKey(Menu.id)) 105 | state = Column(TINYINT(4)) 106 | founder = Column(String(128)) 107 | founder_name = Column(String(128)) 108 | foundtime = Column(DateTime) 109 | updater = Column(String(128)) 110 | updater_name = Column(String(128)) 111 | updatetime = Column(DateTime) 112 | 113 | def __init__(self): 114 | self 115 | 116 | 117 | class Permission(db.Model): 118 | __tablename__ = 'permission' 119 | 120 | id = Column(String(128), primary_key=True) 121 | type = Column(String(128)) 122 | target_id = Column(String(128)) 123 | status = Column(String(32)) 124 | state = Column(TINYINT(4)) 125 | founder = Column(String(128)) 126 | founder_name = Column(String(128)) 127 | foundtime = Column(DateTime) 128 | updater = Column(String(128)) 129 | updater_name = Column(String(128)) 130 | updatetime = Column(DateTime) 131 | 132 | def __init__(self): 133 | self 134 | 135 | 136 | class Role(db.Model): 137 | __tablename__ = 'role' 138 | 139 | id = Column(String(128), primary_key=True) 140 | role_name = Column(String(128)) 141 | role_desc = Column(String(500)) 142 | status = Column(String(32)) 143 | founder = Column(String(128)) 144 | founder_name = Column(String(128)) 145 | foundtime = Column(DateTime) 146 | updater = Column(String(128)) 147 | updater_name = Column(String(128)) 148 | updatetime = Column(DateTime) 149 | 150 | def __init__(self, role_name): 151 | self.role_name = role_name 152 | 153 | 154 | class RolePermission(db.Model): 155 | __tablename__ = 'role_permission' 156 | 157 | id = Column(String(128), primary_key=True) 158 | role_id = Column(String(128)) 159 | permission_id = Column(String(128)) 160 | status = Column(String(32)) 161 | founder = Column(String(128)) 162 | founder_name = Column(String(128)) 163 | foundtime = Column(DateTime) 164 | updater = Column(String(128)) 165 | updater_name = Column(String(128)) 166 | updatetime = Column(DateTime) 167 | 168 | def __init__(self): 169 | self 170 | 171 | 172 | class User(db.Model): 173 | __tablename__ = 'user' 174 | 175 | id = Column(String(128), primary_key=True, unique=True) 176 | username = Column(String(128)) 177 | nickname = Column(String(128)) 178 | password = Column(String(128)) 179 | phone = Column(String(32)) 180 | email = Column(String(128)) 181 | is_children = Column(INTEGER(1)) 182 | parent_id = Column(String(128)) 183 | status = Column(String(32)) 184 | founder = Column(String(128)) 185 | founder_name = Column(String(128)) 186 | foundtime = Column(DateTime) 187 | updater = Column(String(128)) 188 | updater_name = Column(String(128)) 189 | updatetime = Column(DateTime) 190 | 191 | def __init__(self): 192 | self 193 | 194 | # 密码加密 195 | def hash_password(self, password): 196 | self.password = custom_app_context.encrypt(password) 197 | return self.password 198 | 199 | # 密码解析 200 | def verify_password(self, password): 201 | return custom_app_context.verify(password, self.password) 202 | 203 | # 获取token,有效时间 204 | def generate_auth_token(self, expiration=config.settings.TOKEN_EXPIRATION): 205 | s = Serializer(config.settings.SECRET_KEY, expires_in=expiration) 206 | return s.dumps({'id': self.id, 'username': self.username, 'nickname': self.nickname, 'phone': self.phone}) 207 | 208 | # @staticmethod 209 | # def verify_auth_token(token): 210 | # s = Serializer(config.settings.SECRET_KEY) 211 | # try: 212 | # data = s.loads(token) 213 | # print(data) 214 | # except SignatureExpired: 215 | # print('token过期') 216 | # return False # token过期 217 | # except BadSignature: 218 | # print('token无效') 219 | # return False # token无效 220 | # user = User.query.get(data['id']) 221 | # print(user) 222 | # return True 223 | def to_dict(self): 224 | user_info = { 225 | 'id': self.id, 226 | 'username': self.username, 227 | 'phone': self.phone 228 | } 229 | return user_info 230 | 231 | class UserAuth(db.Model): 232 | __tablename__ = 'user_auths' 233 | 234 | id = Column(String(128), primary_key=True) 235 | user_id = Column(String(128)) 236 | third_type = Column(String(32)) 237 | third_key = Column(String(128)) 238 | status = Column(String(32)) 239 | founder_name = Column(String(128)) 240 | foundtime = Column(DateTime) 241 | updater = Column(String(128)) 242 | updater_name = Column(String(128)) 243 | updatetime = Column(DateTime) 244 | founder = Column(String(128)) 245 | 246 | def __init__(self): 247 | self 248 | 249 | 250 | class UserGroup(db.Model): 251 | __tablename__ = 'user_group' 252 | 253 | id = Column(String(128), primary_key=True) 254 | user_id = Column(String(128)) 255 | group_id = Column(String(128)) 256 | status = Column(String(32)) 257 | founder = Column(String(128)) 258 | founder_name = Column(String(128)) 259 | foundtime = Column(DateTime) 260 | updater = Column(String(128)) 261 | updater_name = Column(String(128)) 262 | updatetime = Column(DateTime) 263 | 264 | def __init__(self): 265 | self 266 | 267 | 268 | class UserRole(db.Model): 269 | __tablename__ = 'user_role' 270 | 271 | id = Column(String(128), primary_key=True) 272 | user_id = Column(String(128)) 273 | role_id = Column(String(128)) 274 | status = Column(String(32)) 275 | founder = Column(String(128)) 276 | founder_name = Column(String(128)) 277 | foundtime = Column(DateTime) 278 | updater = Column(String(128)) 279 | updater_name = Column(String(128)) 280 | updatetime = Column(DateTime) 281 | 282 | def __init__(self): 283 | self 284 | -------------------------------------------------------------------------------- /app/site/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/app/site/__init__.py -------------------------------------------------------------------------------- /app/site/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/app/site/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /app/site/__pycache__/routes.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/app/site/__pycache__/routes.cpython-37.pyc -------------------------------------------------------------------------------- /app/site/routes.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from flask import Blueprint, render_template 4 | 5 | log = logging.getLogger(__name__) 6 | 7 | site_blueprint = Blueprint('site', __name__, url_prefix='/', template_folder='templates') 8 | 9 | 10 | @site_blueprint.route('/') 11 | def index(): 12 | return render_template('layout.html') 13 | 14 | -------------------------------------------------------------------------------- /app/site/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Site Example 6 | 7 | 8 | 9 |

10 | My Flask, Blueprint, Flask-RESTPlus and Swagger API Example 11 |

12 | 13 |
14 |

15 | This is the site part of our application, 16 | in this part you could add a front-end 17 | using templates and others tools or frameworks. 18 |

19 |
20 | 21 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /config/__pycache__/settings.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/config/__pycache__/settings.cpython-36.pyc -------------------------------------------------------------------------------- /config/__pycache__/settings.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/config/__pycache__/settings.cpython-37.pyc -------------------------------------------------------------------------------- /config/settings.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Author : Guohao 4 | # @Time : 2019-07-19 13:01 5 | 6 | # Global App setting 7 | 8 | # Flask settings 9 | FLASK_DEBUG = True 10 | SECRET_KEY = '123456' 11 | 12 | # MySQL 数据库配置 13 | SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:123456@localhost:3306/testDB?charset=utf8' 14 | SQLALCHEMY_ENCODING = 'utf-8' 15 | SQLALCHEMY_TRACK_MODIFICATIONS = False # 屏蔽 sql alchemy 的 FSADeprecationWarning 16 | 17 | # Flask-restplus settings 18 | SWAGGER_UI_DOC_EXPANSION = 'list' 19 | RESTPLUS_VALIDATE = True 20 | RESTPLUS_MASK_SWAGGER = False 21 | ERROR_404_HELP = False 22 | 23 | # Token 时效 24 | TOKEN_EXPIRATION = 60 * 60 * 24 25 | 26 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | api: 4 | build: . 5 | ports: 6 | - 5000:5000 -------------------------------------------------------------------------------- /logging.conf: -------------------------------------------------------------------------------- 1 | [loggers] 2 | keys=root,backend 3 | 4 | [handlers] 5 | keys=console 6 | 7 | [formatters] 8 | keys=simple 9 | 10 | [logger_root] 11 | level=DEBUG 12 | handlers=console 13 | 14 | [logger_backend] 15 | level=DEBUG 16 | handlers=console 17 | qualname=backend 18 | propagate=0 19 | 20 | [handler_console] 21 | class=StreamHandler 22 | level=DEBUG 23 | formatter=simple 24 | args=(sys.stdout,) 25 | 26 | [formatter_simple] 27 | format=%(asctime)s - %(name)s - %(levelname)s - %(message)s 28 | datefmt= 29 | -------------------------------------------------------------------------------- /rbac.rp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/rbac.rp -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask 2 | Flask-SQLAlchemy 3 | Flask-RESTPlus -------------------------------------------------------------------------------- /runserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Author : Guohao 4 | # @Time : 2019-07-19 12:02 5 | 6 | import logging.config 7 | 8 | from app import app 9 | from config.settings import FLASK_DEBUG 10 | 11 | logging.config.fileConfig('logging.conf') 12 | log = logging.getLogger(__name__) 13 | 14 | if __name__ == '__main__': 15 | log.info('Starting server') 16 | # 指定host,防止docker无法打开 17 | app.run(host='0.0.0.0', debug=FLASK_DEBUG) -------------------------------------------------------------------------------- /testDb.sql: -------------------------------------------------------------------------------- 1 | -- MySQL dump 10.13 Distrib 5.7.21, for osx10.12 (x86_64) 2 | -- 3 | -- Host: 127.0.0.1 Database: testDB 4 | -- ------------------------------------------------------ 5 | -- Server version 5.7.21 6 | 7 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 8 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 9 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 10 | /*!40101 SET NAMES utf8 */; 11 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; 12 | /*!40103 SET TIME_ZONE='+00:00' */; 13 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 14 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 15 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 16 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 17 | 18 | -- 19 | -- Table structure for table `group` 20 | -- 21 | 22 | DROP TABLE IF EXISTS `group`; 23 | /*!40101 SET @saved_cs_client = @@character_set_client */; 24 | /*!40101 SET character_set_client = utf8 */; 25 | CREATE TABLE `group` ( 26 | `id` varchar(128) NOT NULL, 27 | `groupname` varchar(128) DEFAULT NULL, 28 | `parent_id` varchar(128) DEFAULT NULL COMMENT '父用户组', 29 | `parent_name` varchar(128) DEFAULT NULL COMMENT '父用户组名称', 30 | `status` varchar(32) DEFAULT NULL, 31 | `founder` varchar(128) DEFAULT NULL, 32 | `founder_name` varchar(128) DEFAULT NULL, 33 | `foundtime` datetime DEFAULT NULL, 34 | `updater` varchar(128) DEFAULT NULL, 35 | `updater_name` varchar(128) DEFAULT NULL, 36 | `updatetime` datetime DEFAULT NULL, 37 | PRIMARY KEY (`id`) 38 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户组'; 39 | /*!40101 SET character_set_client = @saved_cs_client */; 40 | 41 | -- 42 | -- Dumping data for table `group` 43 | -- 44 | 45 | LOCK TABLES `group` WRITE; 46 | /*!40000 ALTER TABLE `group` DISABLE KEYS */; 47 | INSERT INTO `group` VALUES ('1','系统用户组','NULL',NULL,'1','NULL','NULL',NULL,'NULL','NULL',NULL),('2','运营用户组','NULL',NULL,'1','NULL','NULL',NULL,'NULL','NULL',NULL),('3','企业用户组','NULL',NULL,'1','NULL','NULL',NULL,'NULL','NULL',NULL),('4','企业1','3',NULL,'1','NULL','NULL',NULL,'NULL','NULL',NULL); 48 | /*!40000 ALTER TABLE `group` ENABLE KEYS */; 49 | UNLOCK TABLES; 50 | 51 | -- 52 | -- Table structure for table `group_role` 53 | -- 54 | 55 | DROP TABLE IF EXISTS `group_role`; 56 | /*!40101 SET @saved_cs_client = @@character_set_client */; 57 | /*!40101 SET character_set_client = utf8 */; 58 | CREATE TABLE `group_role` ( 59 | `id` varchar(128) NOT NULL, 60 | `group_id` varchar(128) DEFAULT NULL, 61 | `role_id` varchar(128) DEFAULT NULL, 62 | `status` varchar(32) DEFAULT NULL, 63 | `founder` varchar(128) DEFAULT NULL, 64 | `founder_name` varchar(128) DEFAULT NULL, 65 | `foundtime` datetime DEFAULT NULL, 66 | `updater` varchar(128) DEFAULT NULL, 67 | `updater_name` varchar(128) DEFAULT NULL, 68 | `updatetime` datetime DEFAULT NULL, 69 | PRIMARY KEY (`id`) 70 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户组与角色关联'; 71 | /*!40101 SET character_set_client = @saved_cs_client */; 72 | 73 | -- 74 | -- Dumping data for table `group_role` 75 | -- 76 | 77 | LOCK TABLES `group_role` WRITE; 78 | /*!40000 ALTER TABLE `group_role` DISABLE KEYS */; 79 | INSERT INTO `group_role` VALUES ('c00381a8-aa8b-11e9-9af6-784f43947f92','1','e4c9bc40-aa0a-11e9-a33f-784f43947f92','1',NULL,NULL,'2019-07-20 09:14:41',NULL,NULL,NULL),('c0047176-aa8b-11e9-9af6-784f43947f92','1','a0c0ffd4-aa1b-11e9-bcb1-784f43947f92','1',NULL,NULL,'2019-07-20 09:14:41',NULL,NULL,NULL); 80 | /*!40000 ALTER TABLE `group_role` ENABLE KEYS */; 81 | UNLOCK TABLES; 82 | 83 | -- 84 | -- Table structure for table `menu` 85 | -- 86 | 87 | DROP TABLE IF EXISTS `menu`; 88 | /*!40101 SET @saved_cs_client = @@character_set_client */; 89 | /*!40101 SET character_set_client = utf8 */; 90 | CREATE TABLE `menu` ( 91 | `id` varchar(128) NOT NULL, 92 | `menu_code` varchar(64) DEFAULT NULL, 93 | `menu_name` varchar(128) DEFAULT NULL, 94 | `menu_icon` varchar(128) DEFAULT NULL, 95 | `menu_path` varchar(128) DEFAULT NULL, 96 | `parent_id` varchar(128) DEFAULT NULL, 97 | `sort` int(11) DEFAULT NULL, 98 | `is_hidden` tinyint(4) DEFAULT '0' COMMENT '1 隐藏 0 显示', 99 | `status` varchar(32) DEFAULT NULL, 100 | `state` tinyint(4) DEFAULT NULL COMMENT '1 有效 0 无效 -1 删除', 101 | `founder` varchar(128) DEFAULT NULL, 102 | `founder_name` varchar(128) DEFAULT NULL, 103 | `foundtime` datetime DEFAULT NULL, 104 | `updater` varchar(128) DEFAULT NULL, 105 | `updater_name` varchar(128) DEFAULT NULL, 106 | `updatetime` datetime DEFAULT NULL, 107 | PRIMARY KEY (`id`), 108 | UNIQUE KEY `menu_menu_code_uindex` (`menu_code`) 109 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='菜单'; 110 | /*!40101 SET character_set_client = @saved_cs_client */; 111 | 112 | -- 113 | -- Dumping data for table `menu` 114 | -- 115 | 116 | LOCK TABLES `menu` WRITE; 117 | /*!40000 ALTER TABLE `menu` DISABLE KEYS */; 118 | /*!40000 ALTER TABLE `menu` ENABLE KEYS */; 119 | UNLOCK TABLES; 120 | 121 | -- 122 | -- Table structure for table `menu_element` 123 | -- 124 | 125 | DROP TABLE IF EXISTS `menu_element`; 126 | /*!40101 SET @saved_cs_client = @@character_set_client */; 127 | /*!40101 SET character_set_client = utf8 */; 128 | CREATE TABLE `menu_element` ( 129 | `id` varchar(128) NOT NULL, 130 | `element_code` varchar(128) DEFAULT NULL, 131 | `element_name` varchar(128) DEFAULT NULL, 132 | `menu_id` varchar(128) DEFAULT NULL, 133 | `state` tinyint(4) DEFAULT NULL COMMENT '1 有效 0 无效 -1 删除', 134 | `founder` varchar(128) DEFAULT NULL, 135 | `founder_name` varchar(128) DEFAULT NULL, 136 | `foundtime` datetime DEFAULT NULL, 137 | `updater` varchar(128) DEFAULT NULL, 138 | `updater_name` varchar(128) DEFAULT NULL, 139 | `updatetime` datetime DEFAULT NULL, 140 | PRIMARY KEY (`id`) 141 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='菜单页面元素'; 142 | /*!40101 SET character_set_client = @saved_cs_client */; 143 | 144 | -- 145 | -- Dumping data for table `menu_element` 146 | -- 147 | 148 | LOCK TABLES `menu_element` WRITE; 149 | /*!40000 ALTER TABLE `menu_element` DISABLE KEYS */; 150 | /*!40000 ALTER TABLE `menu_element` ENABLE KEYS */; 151 | UNLOCK TABLES; 152 | 153 | -- 154 | -- Table structure for table `menu_operation` 155 | -- 156 | 157 | DROP TABLE IF EXISTS `menu_operation`; 158 | /*!40101 SET @saved_cs_client = @@character_set_client */; 159 | /*!40101 SET character_set_client = utf8 */; 160 | CREATE TABLE `menu_operation` ( 161 | `id` varchar(128) NOT NULL, 162 | `operation_code` varchar(128) DEFAULT NULL, 163 | `operation_name` varchar(128) DEFAULT NULL, 164 | `menu_id` varchar(128) DEFAULT NULL, 165 | `state` tinyint(4) DEFAULT NULL COMMENT '1 有效 0 无效 -1 删除', 166 | `founder` varchar(128) DEFAULT NULL, 167 | `founder_name` varchar(128) DEFAULT NULL, 168 | `foundtime` datetime DEFAULT NULL, 169 | `updater` varchar(128) DEFAULT NULL, 170 | `updater_name` varchar(128) DEFAULT NULL, 171 | `updatetime` datetime DEFAULT NULL, 172 | PRIMARY KEY (`id`) 173 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='菜单页面操作'; 174 | /*!40101 SET character_set_client = @saved_cs_client */; 175 | 176 | -- 177 | -- Dumping data for table `menu_operation` 178 | -- 179 | 180 | LOCK TABLES `menu_operation` WRITE; 181 | /*!40000 ALTER TABLE `menu_operation` DISABLE KEYS */; 182 | INSERT INTO `menu_operation` VALUES ('0a4a4e4c-ac2e-11e9-9f5b-784f43947f92','ope1-1','ope1-1',NULL,NULL,NULL,NULL,'2019-07-22 11:08:55',NULL,NULL,NULL),('2','op1-1','op1-2',NULL,NULL,NULL,NULL,'2019-07-22 11:11:47',NULL,NULL,NULL); 183 | /*!40000 ALTER TABLE `menu_operation` ENABLE KEYS */; 184 | UNLOCK TABLES; 185 | 186 | -- 187 | -- Table structure for table `permission` 188 | -- 189 | 190 | DROP TABLE IF EXISTS `permission`; 191 | /*!40101 SET @saved_cs_client = @@character_set_client */; 192 | /*!40101 SET character_set_client = utf8 */; 193 | CREATE TABLE `permission` ( 194 | `id` varchar(128) NOT NULL, 195 | `type` varchar(128) DEFAULT NULL COMMENT '权限类型(menu、menu_element、menu_operation)', 196 | `target_id` varchar(128) DEFAULT NULL COMMENT '权限关联目标id', 197 | `status` varchar(32) DEFAULT NULL, 198 | `state` tinyint(4) DEFAULT NULL COMMENT '1 有效 0 无效 -1 删除', 199 | `founder` varchar(128) DEFAULT NULL, 200 | `founder_name` varchar(128) DEFAULT NULL, 201 | `foundtime` datetime DEFAULT NULL, 202 | `updater` varchar(128) DEFAULT NULL, 203 | `updater_name` varchar(128) DEFAULT NULL, 204 | `updatetime` datetime DEFAULT NULL, 205 | PRIMARY KEY (`id`) 206 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='权限'; 207 | /*!40101 SET character_set_client = @saved_cs_client */; 208 | 209 | -- 210 | -- Dumping data for table `permission` 211 | -- 212 | 213 | LOCK TABLES `permission` WRITE; 214 | /*!40000 ALTER TABLE `permission` DISABLE KEYS */; 215 | /*!40000 ALTER TABLE `permission` ENABLE KEYS */; 216 | UNLOCK TABLES; 217 | 218 | -- 219 | -- Table structure for table `role` 220 | -- 221 | 222 | DROP TABLE IF EXISTS `role`; 223 | /*!40101 SET @saved_cs_client = @@character_set_client */; 224 | /*!40101 SET character_set_client = utf8 */; 225 | CREATE TABLE `role` ( 226 | `id` varchar(128) NOT NULL, 227 | `role_name` varchar(128) DEFAULT NULL, 228 | `role_desc` varchar(500) DEFAULT NULL, 229 | `own` varchar(128) DEFAULT NULL COMMENT '关联所属', 230 | `status` varchar(32) DEFAULT NULL, 231 | `founder` varchar(128) DEFAULT NULL, 232 | `founder_name` varchar(128) DEFAULT NULL, 233 | `foundtime` datetime DEFAULT NULL, 234 | `updater` varchar(128) DEFAULT NULL, 235 | `updater_name` varchar(128) DEFAULT NULL, 236 | `updatetime` datetime DEFAULT NULL, 237 | PRIMARY KEY (`id`) 238 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色'; 239 | /*!40101 SET character_set_client = @saved_cs_client */; 240 | 241 | -- 242 | -- Dumping data for table `role` 243 | -- 244 | 245 | LOCK TABLES `role` WRITE; 246 | /*!40000 ALTER TABLE `role` DISABLE KEYS */; 247 | INSERT INTO `role` VALUES ('8f01cc6a-aa1b-11e9-bcb1-784f43947f92','公司管理员','公司管理员',NULL,'1',NULL,NULL,'2019-07-19 19:51:35',NULL,NULL,NULL),('a0c0ffd4-aa1b-11e9-bcb1-784f43947f92','运营管理员','运营管理员',NULL,'1',NULL,NULL,'2019-07-19 19:52:04',NULL,NULL,NULL),('e4c9bc40-aa0a-11e9-a33f-784f43947f92','系统操作员','仅供系统操作员',NULL,'1',NULL,NULL,'2019-07-19 17:52:17',NULL,NULL,'2019-07-19 17:54:04'); 248 | /*!40000 ALTER TABLE `role` ENABLE KEYS */; 249 | UNLOCK TABLES; 250 | 251 | -- 252 | -- Table structure for table `role_permission` 253 | -- 254 | 255 | DROP TABLE IF EXISTS `role_permission`; 256 | /*!40101 SET @saved_cs_client = @@character_set_client */; 257 | /*!40101 SET character_set_client = utf8 */; 258 | CREATE TABLE `role_permission` ( 259 | `id` varchar(128) NOT NULL, 260 | `role_id` varchar(128) DEFAULT NULL, 261 | `permission_id` varchar(128) DEFAULT NULL, 262 | `status` varchar(32) DEFAULT NULL, 263 | `founder` varchar(128) DEFAULT NULL, 264 | `founder_name` varchar(128) DEFAULT NULL, 265 | `foundtime` datetime DEFAULT NULL, 266 | `updater` varchar(128) DEFAULT NULL, 267 | `updater_name` varchar(128) DEFAULT NULL, 268 | `updatetime` datetime DEFAULT NULL, 269 | PRIMARY KEY (`id`) 270 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色与权限关联表'; 271 | /*!40101 SET character_set_client = @saved_cs_client */; 272 | 273 | -- 274 | -- Dumping data for table `role_permission` 275 | -- 276 | 277 | LOCK TABLES `role_permission` WRITE; 278 | /*!40000 ALTER TABLE `role_permission` DISABLE KEYS */; 279 | /*!40000 ALTER TABLE `role_permission` ENABLE KEYS */; 280 | UNLOCK TABLES; 281 | 282 | -- 283 | -- Table structure for table `test_user` 284 | -- 285 | 286 | DROP TABLE IF EXISTS `test_user`; 287 | /*!40101 SET @saved_cs_client = @@character_set_client */; 288 | /*!40101 SET character_set_client = utf8 */; 289 | CREATE TABLE `test_user` ( 290 | `id` int(11) NOT NULL AUTO_INCREMENT, 291 | `user_name` varchar(32) NOT NULL, 292 | `sex` varchar(2) DEFAULT NULL, 293 | PRIMARY KEY (`id`) 294 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 295 | /*!40101 SET character_set_client = @saved_cs_client */; 296 | 297 | -- 298 | -- Dumping data for table `test_user` 299 | -- 300 | 301 | LOCK TABLES `test_user` WRITE; 302 | /*!40000 ALTER TABLE `test_user` DISABLE KEYS */; 303 | /*!40000 ALTER TABLE `test_user` ENABLE KEYS */; 304 | UNLOCK TABLES; 305 | 306 | -- 307 | -- Table structure for table `user` 308 | -- 309 | 310 | DROP TABLE IF EXISTS `user`; 311 | /*!40101 SET @saved_cs_client = @@character_set_client */; 312 | /*!40101 SET character_set_client = utf8 */; 313 | CREATE TABLE `user` ( 314 | `id` varchar(128) NOT NULL, 315 | `username` varchar(128) DEFAULT NULL COMMENT '用户名', 316 | `nickname` varchar(128) DEFAULT NULL COMMENT ' 昵称', 317 | `password` varchar(128) DEFAULT NULL COMMENT '密码', 318 | `phone` varchar(32) DEFAULT NULL, 319 | `email` varchar(128) DEFAULT NULL, 320 | `is_children` int(1) DEFAULT NULL COMMENT '是否子账号(1 是 0 否)', 321 | `parent_id` varchar(128) DEFAULT NULL COMMENT '父账号id', 322 | `status` varchar(32) DEFAULT NULL, 323 | `founder` varchar(128) DEFAULT NULL, 324 | `founder_name` varchar(128) DEFAULT NULL, 325 | `foundtime` datetime DEFAULT NULL, 326 | `updater` varchar(128) DEFAULT NULL, 327 | `updater_name` varchar(128) DEFAULT NULL, 328 | `updatetime` datetime DEFAULT NULL, 329 | PRIMARY KEY (`id`), 330 | UNIQUE KEY `user_bases_id_uindex` (`id`) 331 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户基础信息表'; 332 | /*!40101 SET character_set_client = @saved_cs_client */; 333 | 334 | -- 335 | -- Dumping data for table `user` 336 | -- 337 | 338 | LOCK TABLES `user` WRITE; 339 | /*!40000 ALTER TABLE `user` DISABLE KEYS */; 340 | INSERT INTO `user` VALUES ('094c273e-b1b7-11e9-b7cf-acde48001122','test','test','$6$rounds=656000$9fAjbja0WfGIoSib$i126f12XdSTbF/eF6tSuu1igHP9/K4nUqeckSD6D1Ci09SdIWM36OVw.lNgMfL6sb7HjfPowas5ByNgNSHFz6.','15208395947',NULL,NULL,NULL,NULL,NULL,NULL,'2019-07-29 12:12:11',NULL,NULL,NULL),('1447c658-aecd-11e9-8084-784f43947f92','newUser1','newUser1','$6$rounds=656000$RziSEcwmmFzk99y2$7jpV.hnHephFf.YTtoWoDU2vEUConMpjBFHhDNHipGan2EDA0v.PjYJ.ZTahVE.L85Mb8TCBQR15HLSrs.hBV.','string',NULL,NULL,NULL,NULL,NULL,NULL,'2019-07-25 19:12:25',NULL,NULL,NULL),('1afa24e6-aecd-11e9-8084-784f43947f92','newUser1','newUser1','$6$rounds=656000$UyoaAdZpsZKAsgRZ$.4SdubVyr2howCqJcbJVoI82.ZrdP2BmLjRPxN70iES3SCdUBgNKvAgiG7EXvDwWRZBCiIgYnLue18cMHQj0j0','string',NULL,NULL,NULL,NULL,NULL,NULL,'2019-07-25 19:12:36',NULL,NULL,NULL),('2','test2','test2',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),('2f9a5f42-aa09-11e9-bc94-784f43947f92','admin','admin','123456','15208395947','511721582@qq.con',0,NULL,'1','1','admin','2019-07-19 05:31:14',NULL,NULL,NULL),('3','ts3','323a',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),('4','test4','4444t',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),('5','test5','test5',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),('503c9cde-a9f9-11e9-8e7f-784f43947f92','郭浩','st过ng','123124',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),('526fa27c-b4f2-11e9-8989-784f43947f92','test2','test2','$6$rounds=656000$zgmIwXbmNTq0C4Rs$809gG8elg0FT4LjCzHLNfoisnouUs2plZVjHSzfEs74T4u2ouJztD3atauEbn2vxMo9H7VApseWKRn5r3HeOX.','15208395947',NULL,NULL,NULL,NULL,NULL,NULL,'2019-08-02 14:54:07',NULL,NULL,NULL),('6','tets6','test6',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),('7','tst7','y7',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),('8','yy8','ert78',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),('8b6bc708-a9f9-11e9-a481-784f43947f92','雪莲','莲','123456','17608017801',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),('9','tets9','te9',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),('9bc01172-aecc-11e9-a1d2-784f43947f92',NULL,'newUser1',NULL,'string',NULL,NULL,NULL,NULL,NULL,NULL,'2019-07-25 19:09:03',NULL,NULL,NULL),('9f274c0a-b4f7-11e9-9c4b-784f43947f92','test8','test7','$6$rounds=656000$10TF0R.y7vvUQtz5$2NZyv6t5PEhS3Uxv6Y6YEBxMXA/pSYNkg0h8w2OOnU8QNowtYODoiZwdJJ4dB5njjFjdCYysHxp7Vdh0bDyJU/','1512321234',NULL,NULL,NULL,NULL,NULL,NULL,'2019-08-02 15:32:04',NULL,NULL,NULL),('ae023064-b4f7-11e9-bef5-784f43947f92','test9','test7','$6$rounds=656000$8CZ2E8BJQhV5wN5r$teZOmMkXX6.9VGFSRRhtOpuSdRTu0mN99CJZBYD0coSILOIbBAKl9zWBZBgQ3M343tY3JxDQbyzjfQxFq10rE0','1512321234',NULL,NULL,NULL,NULL,NULL,NULL,'2019-08-02 15:32:28',NULL,NULL,NULL),('ae1c3780-b4f6-11e9-ac18-784f43947f92','test4','test5','$6$rounds=656000$XmExiA0KyKI1BpBY$iTiw/t9ueEZGyZSxR5wBYnp5YHWPW/zrOZrpi6pRgKD/WCS89IBm5kguXfoNs5i45xkdm5EFLJzbF4J4/Caih0','1512321234',NULL,NULL,NULL,NULL,NULL,NULL,'2019-08-02 15:25:19',NULL,NULL,NULL),('bbb67b02-b4f7-11e9-852b-784f43947f92','test10','test7','$6$rounds=656000$GpDXq/vDDkdCbXzf$Ip71izv0FIBtTuo3FydZI5IpbBatsoiJQqA877zHuD.htSTaZGvbM1HLh0w4QIYkIZYTHvLARWTE6jmTgxqGS0','1512321234',NULL,NULL,NULL,NULL,NULL,NULL,'2019-08-02 15:32:51',NULL,NULL,NULL),('bbd29b08-b4f6-11e9-99ba-784f43947f92','test5','test5','$6$rounds=656000$KKpMhJC0JLoUU532$Bos3sfhJPCOn63jbkz.mdvtFbvUlDA2NVyshUyCd9uA0woisdDdOi6kOGOlpG3Ui6IDaPgb44G5k9n6jPbJHU/','1512321234',NULL,NULL,NULL,NULL,NULL,NULL,'2019-08-02 15:25:42',NULL,NULL,NULL),('c38a9722-aecc-11e9-a1a7-784f43947f92','newUser1','newUser1',NULL,'string',NULL,NULL,NULL,NULL,NULL,NULL,'2019-07-25 19:10:10',NULL,NULL,NULL),('d4c0f754-b4f6-11e9-b42c-784f43947f92','test6','test6','$6$rounds=656000$z9HYISb96yq7TkSt$jaD.MlvJWhmKHNINsycAV7KWozbI19Llq1hEXCZfJpe9daWieIlr6srYV7xsxV2zuJOVG8gie4TN6QlyIomHg1','1512321234',NULL,NULL,NULL,NULL,NULL,NULL,'2019-08-02 15:26:24',NULL,NULL,NULL),('e4147630-b4f7-11e9-a1f3-784f43947f92','test11','test7','$6$rounds=656000$lxQrmUL.EQ.TtfSc$E6MyporfDTv81B00sEdyE9fMPib7RYJV5xqbdhTSESFqHF3axFrUU1lOC9Up/NkpicpOFtsWK7ECg/gh4h6JG/','1512321234',NULL,NULL,NULL,NULL,'094c273e-b1b7-11e9-b7cf-acde48001122','test','2019-08-02 15:33:59',NULL,NULL,NULL),('f2f0e6bc-b4f6-11e9-a604-784f43947f92','test7','test7','$6$rounds=656000$J7qXmUcqud5nfCaB$L9yzFNhZK77OH8pbFv4ol7RbAh.JDI1TrKoJMlin94f.HcDtpPB2qDyh4ovYv0s4r3i.wnV1zPflpVeTFrl3w1','1512321234',NULL,NULL,NULL,NULL,NULL,NULL,'2019-08-02 15:27:15',NULL,NULL,NULL),('f5e2aae2-b4f4-11e9-94a4-784f43947f92','test3','test3','$6$rounds=656000$4OrL/CpA9iLIVT63$u9kAUz1YZ/YjzdXXQwYnuufJ/xbUDcVJyFHfj8SA0JgCC5WCbQ1r55bQAF8WMdgXP3YDakBkdK9vop6irSq5a1','1512321234',NULL,NULL,NULL,NULL,NULL,NULL,'2019-08-02 15:13:01',NULL,NULL,NULL); 341 | /*!40000 ALTER TABLE `user` ENABLE KEYS */; 342 | UNLOCK TABLES; 343 | 344 | -- 345 | -- Table structure for table `user_auths` 346 | -- 347 | 348 | DROP TABLE IF EXISTS `user_auths`; 349 | /*!40101 SET @saved_cs_client = @@character_set_client */; 350 | /*!40101 SET character_set_client = utf8 */; 351 | CREATE TABLE `user_auths` ( 352 | `id` varchar(128) NOT NULL, 353 | `user_id` varchar(128) DEFAULT NULL COMMENT '关联用户user_bases的id', 354 | `third_type` varchar(32) DEFAULT NULL COMMENT '三方登录类型', 355 | `third_key` varchar(128) DEFAULT NULL COMMENT '三方登录唯一标识', 356 | `status` varchar(32) DEFAULT NULL, 357 | `founder_name` varchar(128) DEFAULT NULL, 358 | `foundtime` datetime DEFAULT NULL, 359 | `updater` varchar(128) DEFAULT NULL, 360 | `updater_name` varchar(128) DEFAULT NULL, 361 | `updatetime` datetime DEFAULT NULL, 362 | `founder` varchar(128) DEFAULT NULL, 363 | PRIMARY KEY (`id`) 364 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='三方登录'; 365 | /*!40101 SET character_set_client = @saved_cs_client */; 366 | 367 | -- 368 | -- Dumping data for table `user_auths` 369 | -- 370 | 371 | LOCK TABLES `user_auths` WRITE; 372 | /*!40000 ALTER TABLE `user_auths` DISABLE KEYS */; 373 | /*!40000 ALTER TABLE `user_auths` ENABLE KEYS */; 374 | UNLOCK TABLES; 375 | 376 | -- 377 | -- Table structure for table `user_group` 378 | -- 379 | 380 | DROP TABLE IF EXISTS `user_group`; 381 | /*!40101 SET @saved_cs_client = @@character_set_client */; 382 | /*!40101 SET character_set_client = utf8 */; 383 | CREATE TABLE `user_group` ( 384 | `id` varchar(128) NOT NULL, 385 | `user_id` varchar(128) DEFAULT NULL, 386 | `group_id` varchar(128) DEFAULT NULL, 387 | `status` varchar(32) DEFAULT NULL, 388 | `founder` varchar(128) DEFAULT NULL, 389 | `founder_name` varchar(128) DEFAULT NULL, 390 | `foundtime` datetime DEFAULT NULL, 391 | `updater` varchar(128) DEFAULT NULL, 392 | `updater_name` varchar(128) DEFAULT NULL, 393 | `updatetime` datetime DEFAULT NULL, 394 | PRIMARY KEY (`id`) 395 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户与用户组关联'; 396 | /*!40101 SET character_set_client = @saved_cs_client */; 397 | 398 | -- 399 | -- Dumping data for table `user_group` 400 | -- 401 | 402 | LOCK TABLES `user_group` WRITE; 403 | /*!40000 ALTER TABLE `user_group` DISABLE KEYS */; 404 | /*!40000 ALTER TABLE `user_group` ENABLE KEYS */; 405 | UNLOCK TABLES; 406 | 407 | -- 408 | -- Table structure for table `user_role` 409 | -- 410 | 411 | DROP TABLE IF EXISTS `user_role`; 412 | /*!40101 SET @saved_cs_client = @@character_set_client */; 413 | /*!40101 SET character_set_client = utf8 */; 414 | CREATE TABLE `user_role` ( 415 | `id` varchar(128) NOT NULL, 416 | `user_id` varchar(128) DEFAULT NULL, 417 | `role_id` varchar(128) DEFAULT NULL, 418 | `hosting_start` datetime DEFAULT NULL COMMENT '托管时间开始', 419 | `hosting_end` datetime DEFAULT NULL COMMENT '托管时间结束', 420 | `status` varchar(32) DEFAULT NULL, 421 | `founder` varchar(128) DEFAULT NULL, 422 | `founder_name` varchar(128) DEFAULT NULL, 423 | `foundtime` datetime DEFAULT NULL, 424 | `updater` varchar(128) DEFAULT NULL, 425 | `updater_name` varchar(128) DEFAULT NULL, 426 | `updatetime` datetime DEFAULT NULL, 427 | PRIMARY KEY (`id`) 428 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户角色关联表'; 429 | /*!40101 SET character_set_client = @saved_cs_client */; 430 | 431 | -- 432 | -- Dumping data for table `user_role` 433 | -- 434 | 435 | LOCK TABLES `user_role` WRITE; 436 | /*!40000 ALTER TABLE `user_role` DISABLE KEYS */; 437 | INSERT INTO `user_role` VALUES ('3c6a000a-aa28-11e9-b70b-784f43947f92','503c9cde-a9f9-11e9-8e7f-784f43947f92','e4c9bc40-aa0a-11e9-a33f-784f43947f92',NULL,NULL,'1',NULL,NULL,'2019-07-19 21:22:20',NULL,NULL,NULL),('3c6b5112-aa28-11e9-b70b-784f43947f92','503c9cde-a9f9-11e9-8e7f-784f43947f92','a0c0ffd4-aa1b-11e9-bcb1-784f43947f92',NULL,NULL,'1',NULL,NULL,'2019-07-19 21:22:20',NULL,NULL,NULL),('3c6c30f0-aa28-11e9-b70b-784f43947f92','503c9cde-a9f9-11e9-8e7f-784f43947f92','8f01cc6a-aa1b-11e9-bcb1-784f43947f92',NULL,NULL,'1',NULL,NULL,'2019-07-19 21:22:20',NULL,NULL,NULL); 438 | /*!40000 ALTER TABLE `user_role` ENABLE KEYS */; 439 | UNLOCK TABLES; 440 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; 441 | 442 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 443 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 444 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 445 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 446 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 447 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 448 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 449 | 450 | -- Dump completed on 2019-08-14 14:19:44 451 | -------------------------------------------------------------------------------- /todo.md: -------------------------------------------------------------------------------- 1 | # TODO 2 | ## 主体功能 3 | done:用户组CRUD 4 | 创建用户时关联用户组 5 | done:角色CRUD 6 | done:用户组绑定角色 7 | done:菜单CRUD 8 | 菜单页面元素 9 | 菜单页面操作 10 | 角色关联权限 11 | 12 | ## 代码扩展 13 | 校验 14 | done:分页 15 | done:加密 16 | 17 | pipenv 18 | 19 | -------------------------------------------------------------------------------- /utils/__pycache__/response_code.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/utils/__pycache__/response_code.cpython-37.pyc -------------------------------------------------------------------------------- /utils/__pycache__/token_auth.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DarkSide7H/python-Flask-RBAC/1cc02515ed5495c035eb8d69256a7e2e7a991d39/utils/__pycache__/token_auth.cpython-37.pyc -------------------------------------------------------------------------------- /utils/response_code.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Author : Guohao 4 | # @Time : 2019-08-02 14:04 5 | 6 | # 设置返回参数 7 | class Ret: 8 | SUCCESS = "0" 9 | FAILURE = "4001" 10 | DBERR = "4101" 11 | TOKENERR = "4201" 12 | 13 | ERROR_MAP = { 14 | Ret.SUCCESS: "成功", 15 | Ret.FAILURE: "失败", 16 | Ret.DBERR: "数据库错误", 17 | Ret.TOKENERR: "TOKEN失效" 18 | } -------------------------------------------------------------------------------- /utils/token_auth.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Author : Guohao 4 | # @Time : 2019-08-01 15:20 5 | from flask import jsonify, g 6 | from itsdangerous import SignatureExpired, BadSignature 7 | from app.models.models import User, Serializer 8 | from app import auth 9 | from utils.response_code import Ret 10 | import config.settings 11 | 12 | @auth.error_handler 13 | def error_handler(): 14 | return jsonify(code=Ret.TOKENERR, msg='token无效') 15 | 16 | @auth.verify_token 17 | def verify_token(token): 18 | s = Serializer(config.settings.SECRET_KEY) 19 | try: 20 | data = s.loads(token) 21 | print(data['id'], 'data') 22 | except SignatureExpired: 23 | return False # token过期 24 | except BadSignature: 25 | return False # token无效 26 | if 'id' in data: 27 | g.user = User.query.filter(User.id == data['id']).first() 28 | return True 29 | return False 30 | --------------------------------------------------------------------------------