正在显示
11 个修改的文件
包含
468 行增加
和
52 行删除
| @@ -7,8 +7,8 @@ import time | @@ -7,8 +7,8 @@ import time | ||
| 7 | import configure | 7 | import configure |
| 8 | from app.util import BlueprintApi | 8 | from app.util import BlueprintApi |
| 9 | from app.util import find_class | 9 | from app.util import find_class |
| 10 | -from app.models import db,Table,InsertingLayerName,Database,DES,Task | ||
| 11 | - | 10 | +from app.models import db, Table, InsertingLayerName, Database, DES, Task |
| 11 | +from app.modules.auth.oauth2 import config_oauth | ||
| 12 | from flasgger import Swagger | 12 | from flasgger import Swagger |
| 13 | # from rtree import index | 13 | # from rtree import index |
| 14 | import logging | 14 | import logging |
| @@ -28,6 +28,13 @@ from app.util.component.StructuredPrint import StructurePrint | @@ -28,6 +28,13 @@ from app.util.component.StructuredPrint import StructurePrint | ||
| 28 | from app.util.component.PGUtil import PGUtil | 28 | from app.util.component.PGUtil import PGUtil |
| 29 | import os | 29 | import os |
| 30 | 30 | ||
| 31 | +<<<<<<< HEAD | ||
| 32 | +======= | ||
| 33 | +""" | ||
| 34 | +因为decimal不能序列化,增加Flask对decimal类的解析 | ||
| 35 | +""" | ||
| 36 | + | ||
| 37 | +>>>>>>> 62c596fe02f871582dc30904695c665d1c3fc006 | ||
| 31 | 38 | ||
| 32 | class JSONEncoder(_JSONEncoder): | 39 | class JSONEncoder(_JSONEncoder): |
| 33 | """ | 40 | """ |
| @@ -38,6 +45,7 @@ class JSONEncoder(_JSONEncoder): | @@ -38,6 +45,7 @@ class JSONEncoder(_JSONEncoder): | ||
| 38 | return float(o) | 45 | return float(o) |
| 39 | super(JSONEncoder, self).default(o) | 46 | super(JSONEncoder, self).default(o) |
| 40 | 47 | ||
| 48 | + | ||
| 41 | class Flask(_Flask): | 49 | class Flask(_Flask): |
| 42 | json_encoder = JSONEncoder | 50 | json_encoder = JSONEncoder |
| 43 | 51 | ||
| @@ -57,12 +65,18 @@ def create_app(): | @@ -57,12 +65,18 @@ def create_app(): | ||
| 57 | app.config['echo'] = True | 65 | app.config['echo'] = True |
| 58 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True | 66 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True |
| 59 | app.config['JSON_AS_ASCII'] = False | 67 | app.config['JSON_AS_ASCII'] = False |
| 68 | + app.config['SECRET_KEY'] = configure.SECRET_KEY | ||
| 69 | + app.config['OAUTH2_JWT_ENABLED'] = True | ||
| 70 | + | ||
| 71 | + app.config['OAUTH2_JWT_ISS'] = 'http://localhost:5000' | ||
| 72 | + app.config['OAUTH2_JWT_KEY'] = 'secret-key' | ||
| 73 | + app.config['OAUTH2_JWT_ALG'] = 'HS256' | ||
| 60 | # app.config['SQLALCHEMY_ECHO'] = True | 74 | # app.config['SQLALCHEMY_ECHO'] = True |
| 61 | 75 | ||
| 62 | # 跨域设置 | 76 | # 跨域设置 |
| 63 | CORS(app) | 77 | CORS(app) |
| 64 | 78 | ||
| 65 | - #swagger设置 | 79 | + # swagger设置 |
| 66 | swagger_config = Swagger.DEFAULT_CONFIG | 80 | swagger_config = Swagger.DEFAULT_CONFIG |
| 67 | swagger_config.update(configure.swagger_configure) | 81 | swagger_config.update(configure.swagger_configure) |
| 68 | Swagger(app, config=swagger_config) | 82 | Swagger(app, config=swagger_config) |
| @@ -71,41 +85,47 @@ def create_app(): | @@ -71,41 +85,47 @@ def create_app(): | ||
| 71 | db.init_app(app) | 85 | db.init_app(app) |
| 72 | db.create_all(app=app) | 86 | db.create_all(app=app) |
| 73 | 87 | ||
| 74 | - | ||
| 75 | # 日志 | 88 | # 日志 |
| 76 | logging.basicConfig(level=logging.INFO) | 89 | logging.basicConfig(level=logging.INFO) |
| 77 | - log_file = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))),"logs","log.txt") | ||
| 78 | - handler = logging.FileHandler(log_file, encoding='UTF-8') # 设置日志字符集和存储路径名字 | ||
| 79 | - logging_format = logging.Formatter('[%(levelname)s] %(asctime)s %(message)s') | 90 | + log_file = os.path.join(os.path.dirname(os.path.dirname( |
| 91 | + os.path.realpath(__file__))), "logs", "log.txt") | ||
| 92 | + handler = logging.FileHandler( | ||
| 93 | + log_file, encoding='UTF-8') # 设置日志字符集和存储路径名字 | ||
| 94 | + logging_format = logging.Formatter( | ||
| 95 | + '[%(levelname)s] %(asctime)s %(message)s') | ||
| 80 | handler.setFormatter(logging_format) | 96 | handler.setFormatter(logging_format) |
| 81 | app.logger.addHandler(handler) | 97 | app.logger.addHandler(handler) |
| 82 | - | ||
| 83 | - | 98 | + |
| 99 | + # 配置使用鉴权组件,不写无法认证授权 | ||
| 100 | + config_oauth(app) | ||
| 101 | + | ||
| 84 | # 注册blueprint,查找BlueprintApi的子类 | 102 | # 注册blueprint,查找BlueprintApi的子类 |
| 85 | for scan in configure.scan_module: | 103 | for scan in configure.scan_module: |
| 86 | for api in find_class(scan, BlueprintApi): | 104 | for api in find_class(scan, BlueprintApi): |
| 87 | app.register_blueprint(api.bp) | 105 | app.register_blueprint(api.bp) |
| 88 | 106 | ||
| 89 | - | ||
| 90 | # 入库监测线程 | 107 | # 入库监测线程 |
| 108 | + | ||
| 91 | @app.before_first_request | 109 | @app.before_first_request |
| 92 | def data_entry_process(): | 110 | def data_entry_process(): |
| 93 | StructurePrint.print("start listen") | 111 | StructurePrint.print("start listen") |
| 94 | process = threading.Thread(target=data_entry_center) | 112 | process = threading.Thread(target=data_entry_center) |
| 95 | process.start() | 113 | process.start() |
| 114 | + | ||
| 115 | + # 不检测https | ||
| 116 | + os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' | ||
| 117 | + | ||
| 96 | 118 | ||
| 97 | return app | 119 | return app |
| 98 | 120 | ||
| 99 | 121 | ||
| 100 | - | ||
| 101 | - | ||
| 102 | def data_entry_center(): | 122 | def data_entry_center(): |
| 103 | running_dict = {} | 123 | running_dict = {} |
| 104 | - sys_session: Session = PGUtil.get_db_session(configure.SQLALCHEMY_DATABASE_URI) | 124 | + sys_session: Session = PGUtil.get_db_session( |
| 125 | + configure.SQLALCHEMY_DATABASE_URI) | ||
| 105 | 126 | ||
| 106 | while True: | 127 | while True: |
| 107 | 128 | ||
| 108 | - | ||
| 109 | try: | 129 | try: |
| 110 | time.sleep(3) | 130 | time.sleep(3) |
| 111 | 131 | ||
| @@ -114,10 +134,11 @@ def data_entry_center(): | @@ -114,10 +134,11 @@ def data_entry_center(): | ||
| 114 | 134 | ||
| 115 | # structured_print(running_dict.__len__().__str__()) | 135 | # structured_print(running_dict.__len__().__str__()) |
| 116 | 136 | ||
| 117 | - for process,layer_names in running_dict.items(): | 137 | + for process, layer_names in running_dict.items(): |
| 118 | if not process.is_alive(): | 138 | if not process.is_alive(): |
| 119 | for l in layer_names: | 139 | for l in layer_names: |
| 120 | - inserted = sys_session.query(InsertingLayerName).filter_by(name=l).one_or_none() | 140 | + inserted = sys_session.query( |
| 141 | + InsertingLayerName).filter_by(name=l).one_or_none() | ||
| 121 | if inserted: | 142 | if inserted: |
| 122 | sys_session.delete(inserted) | 143 | sys_session.delete(inserted) |
| 123 | sys_session.commit() | 144 | sys_session.commit() |
| @@ -129,7 +150,8 @@ def data_entry_center(): | @@ -129,7 +150,8 @@ def data_entry_center(): | ||
| 129 | 150 | ||
| 130 | # 入库进程少于阈值,开启入库进程 | 151 | # 入库进程少于阈值,开启入库进程 |
| 131 | 152 | ||
| 132 | - inter_size = sys_session.query(distinct(InsertingLayerName.task_guid)).count() | 153 | + inter_size = sys_session.query( |
| 154 | + distinct(InsertingLayerName.task_guid)).count() | ||
| 133 | 155 | ||
| 134 | if inter_size < configure.entry_data_thread: | 156 | if inter_size < configure.entry_data_thread: |
| 135 | # 锁表啊 | 157 | # 锁表啊 |
| @@ -139,28 +161,28 @@ def data_entry_center(): | @@ -139,28 +161,28 @@ def data_entry_center(): | ||
| 139 | try: | 161 | try: |
| 140 | parameter = json.loads(ready_task.parameter) | 162 | parameter = json.loads(ready_task.parameter) |
| 141 | StructurePrint.print("检测到入库任务") | 163 | StructurePrint.print("检测到入库任务") |
| 142 | - ready_task.state=2 | ||
| 143 | - ready_task.process="入库中" | 164 | + ready_task.state = 2 |
| 165 | + ready_task.process = "入库中" | ||
| 144 | sys_session.commit() | 166 | sys_session.commit() |
| 145 | 167 | ||
| 146 | - metas: list = json.loads(parameter.get("meta").__str__()) | 168 | + metas: list = json.loads( |
| 169 | + parameter.get("meta").__str__()) | ||
| 147 | parameter["meta"] = metas | 170 | parameter["meta"] = metas |
| 148 | 171 | ||
| 149 | - | ||
| 150 | - database = sys_session.query(Database).filter_by(guid=ready_task.database_guid).one_or_none() | ||
| 151 | - pg_ds: DataSource = PGUtil.open_pg_data_source(1,DES.decode(database.sqlalchemy_uri)) | 172 | + database = sys_session.query(Database).filter_by( |
| 173 | + guid=ready_task.database_guid).one_or_none() | ||
| 174 | + pg_ds: DataSource = PGUtil.open_pg_data_source( | ||
| 175 | + 1, DES.decode(database.sqlalchemy_uri)) | ||
| 152 | 176 | ||
| 153 | this_task_layer = [] | 177 | this_task_layer = [] |
| 154 | for meta in metas: | 178 | for meta in metas: |
| 155 | overwrite = parameter.get("overwrite", "no") | 179 | overwrite = parameter.get("overwrite", "no") |
| 156 | 180 | ||
| 157 | - | ||
| 158 | - | ||
| 159 | for layer_name_origin, layer_name in meta.get("layer").items(): | 181 | for layer_name_origin, layer_name in meta.get("layer").items(): |
| 160 | origin_name = layer_name | 182 | origin_name = layer_name |
| 161 | no = 1 | 183 | no = 1 |
| 162 | 184 | ||
| 163 | - while (overwrite.__eq__("no") and pg_ds.GetLayerByName(layer_name)) or sys_session.query(InsertingLayerName).filter_by(name=layer_name).one_or_none() : | 185 | + while (overwrite.__eq__("no") and pg_ds.GetLayerByName(layer_name)) or sys_session.query(InsertingLayerName).filter_by(name=layer_name).one_or_none(): |
| 164 | layer_name = origin_name + "_{}".format(no) | 186 | layer_name = origin_name + "_{}".format(no) |
| 165 | no += 1 | 187 | no += 1 |
| 166 | 188 | ||
| @@ -176,7 +198,8 @@ def data_entry_center(): | @@ -176,7 +198,8 @@ def data_entry_center(): | ||
| 176 | meta["layer"][layer_name_origin] = layer_name | 198 | meta["layer"][layer_name_origin] = layer_name |
| 177 | 199 | ||
| 178 | pg_ds.Destroy() | 200 | pg_ds.Destroy() |
| 179 | - entry_data_process = multiprocessing.Process(target=EntryDataVacuate().entry,args=(parameter,)) | 201 | + entry_data_process = multiprocessing.Process( |
| 202 | + target=EntryDataVacuate().entry, args=(parameter,)) | ||
| 180 | entry_data_process.start() | 203 | entry_data_process.start() |
| 181 | running_dict[entry_data_process] = this_task_layer | 204 | running_dict[entry_data_process] = this_task_layer |
| 182 | except Exception as e: | 205 | except Exception as e: |
| @@ -189,4 +212,4 @@ def data_entry_center(): | @@ -189,4 +212,4 @@ def data_entry_center(): | ||
| 189 | sys_session.commit() | 212 | sys_session.commit() |
| 190 | except Exception as e: | 213 | except Exception as e: |
| 191 | sys_session.commit() | 214 | sys_session.commit() |
| 192 | - StructurePrint.print(e.__str__(),"error") | ||
| 215 | + StructurePrint.print(e.__str__(), "error") |
app/modules/auth/__init__.py
0 → 100644
| 1 | +from app.util import BlueprintApi | ||
| 2 | +from app.util import BlueprintApi | ||
| 3 | +from flask import Blueprint, render_template, redirect, url_for, request, session, jsonify | ||
| 4 | +from .models import * | ||
| 5 | +from werkzeug.security import gen_salt | ||
| 6 | +import time | ||
| 7 | +from .oauth2 import authorization, require_oauth, generate_user_info | ||
| 8 | +from authlib.oauth2 import OAuth2Error | ||
| 9 | +from authlib.integrations.flask_oauth2 import current_token | ||
| 10 | + | ||
| 11 | +def current_user(): | ||
| 12 | + if 'id' in session: | ||
| 13 | + uid = session['id'] | ||
| 14 | + return User.query.get(uid) | ||
| 15 | + return None | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +def split_by_crlf(s): | ||
| 19 | + return [v for v in s.splitlines() if v] | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +class DataManager(BlueprintApi): | ||
| 23 | + bp = Blueprint("Auth", __name__, url_prefix="/auth") | ||
| 24 | + | ||
| 25 | + @staticmethod | ||
| 26 | + @bp.route('/test', methods=('GET', 'POST')) | ||
| 27 | + def Test(): | ||
| 28 | + res = {} | ||
| 29 | + try: | ||
| 30 | + res['user'] = User.query.all() | ||
| 31 | + except Exception as e: | ||
| 32 | + raise e | ||
| 33 | + return res | ||
| 34 | + | ||
| 35 | + @staticmethod | ||
| 36 | + @bp.route('/', methods=('GET', 'POST')) | ||
| 37 | + def test(): | ||
| 38 | + if request.method == 'POST': | ||
| 39 | + username = request.form['username'] | ||
| 40 | + password = request.form['password'] | ||
| 41 | + user = User.query.filter_by(username=username).first() | ||
| 42 | + if not user: | ||
| 43 | + user = User(username=username, | ||
| 44 | + password=password, role='admin') | ||
| 45 | + db.session.add(user) | ||
| 46 | + db.session.commit() | ||
| 47 | + session['id'] = user.id | ||
| 48 | + return redirect('/auth') | ||
| 49 | + user = current_user() | ||
| 50 | + if user: | ||
| 51 | + clients = OAuth2Client.query.filter_by(user_id=user.id).all() | ||
| 52 | + else: | ||
| 53 | + clients = [] | ||
| 54 | + return render_template('auth/login.html', user=user, clients=clients) | ||
| 55 | + | ||
| 56 | + | ||
| 57 | + | ||
| 58 | + @staticmethod | ||
| 59 | + @bp.route('/create_client', methods=('GET', 'POST')) | ||
| 60 | + def create_client(): | ||
| 61 | + user = current_user() | ||
| 62 | + if not user: | ||
| 63 | + return redirect('/auth') | ||
| 64 | + if request.method == 'GET': | ||
| 65 | + return render_template('auth/create_client.html') | ||
| 66 | + form = request.form | ||
| 67 | + client_id = gen_salt(24) | ||
| 68 | + client = OAuth2Client(client_id=client_id, user_id=user.id) | ||
| 69 | + # Mixin doesn't set the issue_at date | ||
| 70 | + client.client_id_issued_at = int(time.time()) | ||
| 71 | + if client.token_endpoint_auth_method == 'none': | ||
| 72 | + client.client_secret = '' | ||
| 73 | + else: | ||
| 74 | + client.client_secret = gen_salt(48) | ||
| 75 | + client_metadata = { | ||
| 76 | + "client_name": form["client_name"], | ||
| 77 | + "client_uri": form["client_uri"], | ||
| 78 | + "grant_types": split_by_crlf(form["grant_type"]), | ||
| 79 | + "redirect_uris": split_by_crlf(form["redirect_uri"]), | ||
| 80 | + "response_types": split_by_crlf(form["response_type"]), | ||
| 81 | + "scope": form["scope"], | ||
| 82 | + "token_endpoint_auth_method": form["token_endpoint_auth_method"] | ||
| 83 | + } | ||
| 84 | + client.set_client_metadata(client_metadata) | ||
| 85 | + db.session.add(client) | ||
| 86 | + db.session.commit() | ||
| 87 | + return redirect('/auth') | ||
| 88 | + | ||
| 89 | + @staticmethod | ||
| 90 | + @bp.route('/authorize', methods=('GET', 'POST')) | ||
| 91 | + def authorize(): | ||
| 92 | + user = current_user() | ||
| 93 | + if request.method == 'GET': | ||
| 94 | + try: | ||
| 95 | + grant = authorization.validate_consent_request(end_user=user) | ||
| 96 | + except OAuth2Error as error: | ||
| 97 | + return jsonify(dict(error.get_body())) | ||
| 98 | + return render_template('auth/authorize.html', user=user, grant=grant) | ||
| 99 | + if not user and 'username' in request.form: | ||
| 100 | + username = request.form.get('username') | ||
| 101 | + user = User.query.filter_by(username=username).first() | ||
| 102 | + if request.form['confirm']: | ||
| 103 | + grant_user = user | ||
| 104 | + else: | ||
| 105 | + grant_user = None | ||
| 106 | + return authorization.create_authorization_response(grant_user=grant_user) | ||
| 107 | + | ||
| 108 | + | ||
| 109 | + @staticmethod | ||
| 110 | + @bp.route('/token', methods=['POST']) | ||
| 111 | + def issue_token(): | ||
| 112 | + return authorization.create_token_response() | ||
| 113 | + | ||
| 114 | + @staticmethod | ||
| 115 | + @bp.route('/userinfo') | ||
| 116 | + @require_oauth('profile') | ||
| 117 | + def api_me(): | ||
| 118 | + return jsonify(generate_user_info(current_token.user, current_token.scope)) |
app/modules/auth/models/__init__.py
0 → 100644
| 1 | +from flask_sqlalchemy import sqlalchemy | ||
| 2 | +from sqlalchemy import Column, Integer, Text, Time, ForeignKey | ||
| 3 | +from app.models import db | ||
| 4 | +from authlib.integrations.sqla_oauth2 import ( | ||
| 5 | + OAuth2ClientMixin, | ||
| 6 | + OAuth2TokenMixin, | ||
| 7 | + OAuth2AuthorizationCodeMixin | ||
| 8 | +) | ||
| 9 | +from sqlalchemy.orm import relationship | ||
| 10 | + | ||
| 11 | + | ||
| 12 | +class User (db.Model): | ||
| 13 | + ''' | ||
| 14 | + 用户信息表 | ||
| 15 | + ''' | ||
| 16 | + __tablename__ = "dmdms_user" | ||
| 17 | + id = Column(Integer, primary_key=True) | ||
| 18 | + username = Column(Text) | ||
| 19 | + password = Column(Text) | ||
| 20 | + company = Column(Text) | ||
| 21 | + position = Column(Text) | ||
| 22 | + phone = Column(Text) | ||
| 23 | + email = Column(Text) | ||
| 24 | + create_time = Column(Time) | ||
| 25 | + update_time = Column(Time) | ||
| 26 | + role = Column(Text) | ||
| 27 | + | ||
| 28 | + def __str__(self): | ||
| 29 | + return self.username | ||
| 30 | + | ||
| 31 | + def get_user_id(self): | ||
| 32 | + return self.id | ||
| 33 | + | ||
| 34 | + | ||
| 35 | +class OAuth2Client(db.Model, OAuth2ClientMixin): | ||
| 36 | + __tablename__ = 'oauth2_client' | ||
| 37 | + | ||
| 38 | + id = Column(Integer, primary_key=True) | ||
| 39 | + user_id = Column( | ||
| 40 | + Integer, ForeignKey('dmdms_user.id', ondelete='CASCADE')) | ||
| 41 | + user = relationship('User') | ||
| 42 | + | ||
| 43 | + | ||
| 44 | +class OAuth2AuthorizationCode(db.Model, OAuth2AuthorizationCodeMixin): | ||
| 45 | + __tablename__ = 'oauth2_code' | ||
| 46 | + | ||
| 47 | + id = Column(Integer, primary_key=True) | ||
| 48 | + user_id = Column( | ||
| 49 | + Integer, ForeignKey('dmdms_user.id', ondelete='CASCADE')) | ||
| 50 | + user = relationship('User') | ||
| 51 | + | ||
| 52 | + | ||
| 53 | +class OAuth2Token(db.Model, OAuth2TokenMixin): | ||
| 54 | + __tablename__ = 'oauth2_token' | ||
| 55 | + | ||
| 56 | + id = Column(Integer, primary_key=True) | ||
| 57 | + user_id = Column( | ||
| 58 | + Integer, ForeignKey('dmdms_user.id', ondelete='CASCADE')) | ||
| 59 | + user = relationship('User') |
app/modules/auth/oauth2.py
0 → 100644
| 1 | +from authlib.integrations.flask_oauth2 import ( | ||
| 2 | + AuthorizationServer, ResourceProtector) | ||
| 3 | +from authlib.integrations.sqla_oauth2 import ( | ||
| 4 | + create_query_client_func, | ||
| 5 | + create_save_token_func, | ||
| 6 | + create_bearer_token_validator, | ||
| 7 | +) | ||
| 8 | +from authlib.oauth2.rfc6749.grants import ( | ||
| 9 | + AuthorizationCodeGrant as _AuthorizationCodeGrant, | ||
| 10 | +) | ||
| 11 | +from authlib.oidc.core.grants import ( | ||
| 12 | + OpenIDCode as _OpenIDCode, | ||
| 13 | + OpenIDImplicitGrant as _OpenIDImplicitGrant, | ||
| 14 | + OpenIDHybridGrant as _OpenIDHybridGrant, | ||
| 15 | +) | ||
| 16 | +from authlib.oidc.core import UserInfo | ||
| 17 | +from werkzeug.security import gen_salt | ||
| 18 | +from .models import db, User | ||
| 19 | +from .models import OAuth2Client, OAuth2AuthorizationCode, OAuth2Token | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +DUMMY_JWT_CONFIG = { | ||
| 23 | + 'key': 'secret-key', | ||
| 24 | + 'alg': 'HS256', | ||
| 25 | + 'iss': 'https://authlib.org', | ||
| 26 | + 'exp': 7200, | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +def exists_nonce(nonce, req): | ||
| 30 | + exists = OAuth2AuthorizationCode.query.filter_by( | ||
| 31 | + client_id=req.client_id, nonce=nonce | ||
| 32 | + ).first() | ||
| 33 | + return bool(exists) | ||
| 34 | + | ||
| 35 | + | ||
| 36 | +def generate_user_info(user, scope): | ||
| 37 | + return UserInfo(sub=str(user.id), name=user.username) | ||
| 38 | + | ||
| 39 | + | ||
| 40 | +def create_authorization_code(client, grant_user, request): | ||
| 41 | + code = gen_salt(48) | ||
| 42 | + nonce = request.data.get('nonce') | ||
| 43 | + item = OAuth2AuthorizationCode( | ||
| 44 | + code=code, | ||
| 45 | + client_id=client.client_id, | ||
| 46 | + redirect_uri=request.redirect_uri, | ||
| 47 | + scope=request.scope, | ||
| 48 | + user_id=grant_user.id, | ||
| 49 | + nonce=nonce, | ||
| 50 | + ) | ||
| 51 | + db.session.add(item) | ||
| 52 | + db.session.commit() | ||
| 53 | + return code | ||
| 54 | + | ||
| 55 | + | ||
| 56 | +class AuthorizationCodeGrant(_AuthorizationCodeGrant): | ||
| 57 | + def create_authorization_code(self, client, grant_user, request): | ||
| 58 | + return create_authorization_code(client, grant_user, request) | ||
| 59 | + | ||
| 60 | + def parse_authorization_code(self, code, client): | ||
| 61 | + item = OAuth2AuthorizationCode.query.filter_by( | ||
| 62 | + code=code, client_id=client.client_id).first() | ||
| 63 | + if item and not item.is_expired(): | ||
| 64 | + return item | ||
| 65 | + | ||
| 66 | + def delete_authorization_code(self, authorization_code): | ||
| 67 | + db.session.delete(authorization_code) | ||
| 68 | + db.session.commit() | ||
| 69 | + | ||
| 70 | + def authenticate_user(self, authorization_code): | ||
| 71 | + return User.query.get(authorization_code.user_id) | ||
| 72 | + | ||
| 73 | + | ||
| 74 | +class OpenIDCode(_OpenIDCode): | ||
| 75 | + def exists_nonce(self, nonce, request): | ||
| 76 | + return exists_nonce(nonce, request) | ||
| 77 | + | ||
| 78 | + def get_jwt_config(self, grant): | ||
| 79 | + return DUMMY_JWT_CONFIG | ||
| 80 | + | ||
| 81 | + def generate_user_info(self, user, scope): | ||
| 82 | + return generate_user_info(user, scope) | ||
| 83 | + | ||
| 84 | + | ||
| 85 | +class ImplicitGrant(_OpenIDImplicitGrant): | ||
| 86 | + def exists_nonce(self, nonce, request): | ||
| 87 | + return exists_nonce(nonce, request) | ||
| 88 | + | ||
| 89 | + def get_jwt_config(self, grant): | ||
| 90 | + return DUMMY_JWT_CONFIG | ||
| 91 | + | ||
| 92 | + def generate_user_info(self, user, scope): | ||
| 93 | + return generate_user_info(user, scope) | ||
| 94 | + | ||
| 95 | + | ||
| 96 | +class HybridGrant(_OpenIDHybridGrant): | ||
| 97 | + def create_authorization_code(self, client, grant_user, request): | ||
| 98 | + return create_authorization_code(client, grant_user, request) | ||
| 99 | + | ||
| 100 | + def exists_nonce(self, nonce, request): | ||
| 101 | + return exists_nonce(nonce, request) | ||
| 102 | + | ||
| 103 | + def get_jwt_config(self): | ||
| 104 | + return DUMMY_JWT_CONFIG | ||
| 105 | + | ||
| 106 | + def generate_user_info(self, user, scope): | ||
| 107 | + return generate_user_info(user, scope) | ||
| 108 | + | ||
| 109 | + | ||
| 110 | +authorization = AuthorizationServer() | ||
| 111 | +require_oauth = ResourceProtector() | ||
| 112 | + | ||
| 113 | + | ||
| 114 | +def config_oauth(app): | ||
| 115 | + query_client = create_query_client_func(db.session, OAuth2Client) | ||
| 116 | + save_token = create_save_token_func(db.session, OAuth2Token) | ||
| 117 | + authorization.init_app( | ||
| 118 | + app, | ||
| 119 | + query_client=query_client, | ||
| 120 | + save_token=save_token | ||
| 121 | + ) | ||
| 122 | + | ||
| 123 | + # support all openid grants | ||
| 124 | + authorization.register_grant(AuthorizationCodeGrant, [ | ||
| 125 | + OpenIDCode(require_nonce=True), | ||
| 126 | + ]) | ||
| 127 | + authorization.register_grant(ImplicitGrant) | ||
| 128 | + authorization.register_grant(HybridGrant) | ||
| 129 | + | ||
| 130 | + # protect resource | ||
| 131 | + bearer_cls = create_bearer_token_validator(db.session, OAuth2Token) | ||
| 132 | + require_oauth.register_token_validator(bearer_cls()) |
app/templates/auth/authorize.html
0 → 100644
| 1 | +<p>{{grant.client.client_name}} is requesting: | ||
| 2 | +<strong>{{ grant.request.scope }}</strong> | ||
| 3 | +</p> | ||
| 4 | + | ||
| 5 | +<form action="" method="post"> | ||
| 6 | + <label> | ||
| 7 | + <input type="checkbox" name="confirm"> | ||
| 8 | + <span>Consent?</span> | ||
| 9 | + </label> | ||
| 10 | + {% if not user %} | ||
| 11 | + <p>You haven't logged in. Log in with:</p> | ||
| 12 | + <div> | ||
| 13 | + <input type="text" name="username"> | ||
| 14 | + </div> | ||
| 15 | + {% endif %} | ||
| 16 | + <br> | ||
| 17 | + <button>Submit</button> | ||
| 18 | +</form> |
app/templates/auth/create_client.html
0 → 100644
| 1 | +<style> | ||
| 2 | + label, label > span { display: block; } | ||
| 3 | + label { margin: 15px 0; } | ||
| 4 | +</style> | ||
| 5 | + | ||
| 6 | +<a href="/">Home</a> | ||
| 7 | + | ||
| 8 | +<form action="" method="post"> | ||
| 9 | + <label> | ||
| 10 | + <span>Client Name</span> | ||
| 11 | + <input type="text" name="client_name"> | ||
| 12 | + </label> | ||
| 13 | + <label> | ||
| 14 | + <span>Client URI</span> | ||
| 15 | + <input type="url" name="client_uri"> | ||
| 16 | + </label> | ||
| 17 | + <label> | ||
| 18 | + <span>Allowed Scope</span> | ||
| 19 | + <input type="text" name="scope"> | ||
| 20 | + </label> | ||
| 21 | + <label> | ||
| 22 | + <span>Redirect URIs</span> | ||
| 23 | + <textarea name="redirect_uri" cols="30" rows="10"></textarea> | ||
| 24 | + </label> | ||
| 25 | + <label> | ||
| 26 | + <span>Allowed Grant Types</span> | ||
| 27 | + <textarea name="grant_type" cols="30" rows="10"></textarea> | ||
| 28 | + </label> | ||
| 29 | + <label> | ||
| 30 | + <span>Allowed Response Types</span> | ||
| 31 | + <textarea name="response_type" cols="30" rows="10"></textarea> | ||
| 32 | + </label> | ||
| 33 | + <label> | ||
| 34 | + <span>Token Endpoint Auth Method</span> | ||
| 35 | + <select name="token_endpoint_auth_method"> | ||
| 36 | + <option value="client_secret_basic">client_secret_basic</option> | ||
| 37 | + <option value="client_secret_post">client_secret_post</option> | ||
| 38 | + <option value="none">none</option> | ||
| 39 | + </select> | ||
| 40 | + </label> | ||
| 41 | + <button>Submit</button> | ||
| 42 | +</form> |
app/templates/auth/login.html
0 → 100644
| 1 | +{% if user %} | ||
| 2 | + <style>pre{white-space:wrap}</style> | ||
| 3 | +<div>Logged in as <strong>{{user}}</strong></div> | ||
| 4 | + | ||
| 5 | +{% for client in clients %} | ||
| 6 | +<pre> | ||
| 7 | +{{ client.client_info|tojson }} | ||
| 8 | +{{ client.client_metadata|tojson }} | ||
| 9 | +</pre> | ||
| 10 | +<hr> | ||
| 11 | +{% endfor %} | ||
| 12 | + | ||
| 13 | +<br><a href="{{ url_for('.create_client') }}">Create Client</a> | ||
| 14 | + | ||
| 15 | +{% else %} | ||
| 16 | +<form action="" method="post"> | ||
| 17 | + <input type="text" name="username" placeholder="账号"> | ||
| 18 | + <input type="text" name="password" placeholder="密码"> | ||
| 19 | + <button type="submit">Login / Signup</button> | ||
| 20 | +</form> | ||
| 21 | +{% endif %} |
| @@ -3,15 +3,16 @@ | @@ -3,15 +3,16 @@ | ||
| 3 | # 程序部署ip:host | 3 | # 程序部署ip:host |
| 4 | deploy_ip_host = "172.26.99.160:8840" | 4 | deploy_ip_host = "172.26.99.160:8840" |
| 5 | # 系统数据库 | 5 | # 系统数据库 |
| 6 | -SQLALCHEMY_DATABASE_URI = "postgresql://postgres:chinadci@172.26.99.160:5432/dmap_dms_test" | 6 | +SQLALCHEMY_DATABASE_URI = "postgresql://postgres:postgres@172.26.40.254:5433/dmap_dms_test" |
| 7 | 7 | ||
| 8 | 8 | ||
| 9 | # 部署模式cluster,standalone | 9 | # 部署模式cluster,standalone |
| 10 | -deployment_mode="cluster" | 10 | +deployment_mode = "cluster" |
| 11 | # 部署模式味cluster时有用,master,slave | 11 | # 部署模式味cluster时有用,master,slave |
| 12 | -application_name="master" | 12 | +application_name = "master" |
| 13 | 13 | ||
| 14 | # 固定配置不需要修改 | 14 | # 固定配置不需要修改 |
| 15 | -swagger_configure={"title":"DMapManager"} | 15 | +swagger_configure = {"title": "DMapManager"} |
| 16 | entry_data_thread = 3 | 16 | entry_data_thread = 3 |
| 17 | -scan_module = ["app.modules"]# API所在的模块 | 17 | +scan_module = ["app.modules"] # API所在的模块 |
| 18 | +SECRET_KEY = b'_5#y2L"F4Q8z\n\xec]/' |
| 1 | -flask==1.1.2 | ||
| 2 | -SQLAlchemy==1.3.17 | ||
| 3 | -Flask-SQLAlchemy==2.4.3 | ||
| 4 | -gevent==20.9.0 | ||
| 5 | -gunicorn==20.0.4 | ||
| 6 | -flask_cors==3.0.8 | ||
| 7 | -flasgger==0.9.5 | ||
| 8 | -GDAL==3.2.1 | ||
| 9 | -psycopg2==2.8.5 | ||
| 10 | -pyDes==2.0.1 | ||
| 11 | -gevent-websocket==0.10.1 | ||
| 12 | -Pillow==8.1.2 | ||
| 13 | -#Rtree==0.9.7 | ||
| 14 | -opencv-python==4.5.1.48 | ||
| 15 | -psutil==5.8.0 | ||
| 16 | -mod_wsgi==4.8.0 | ||
| 1 | +flask==1.1.2 | ||
| 2 | +SQLAlchemy==1.3.17 | ||
| 3 | +Flask-SQLAlchemy==2.4.3 | ||
| 4 | +gevent==20.9.0 | ||
| 5 | +gunicorn==20.0.4 | ||
| 6 | +flask_cors==3.0.8 | ||
| 7 | +flasgger==0.9.5 | ||
| 8 | +GDAL==3.2.1 | ||
| 9 | +psycopg2==2.8.5 | ||
| 10 | +pyDes==2.0.1 | ||
| 11 | +gevent-websocket==0.10.1 | ||
| 12 | +Pillow==8.1.2 | ||
| 13 | +#Rtree==0.9.7 | ||
| 14 | +opencv-python==4.5.1.48 | ||
| 15 | +pstuil==5.8.0 | ||
| 16 | +mod_wsgi==4.8.0 | ||
| 17 | +Authlib==0.13 | ||
| 18 | + |
| @@ -3,5 +3,4 @@ from flask import Flask | @@ -3,5 +3,4 @@ from flask import Flask | ||
| 3 | from app import create_app | 3 | from app import create_app |
| 4 | app:Flask = create_app() | 4 | app:Flask = create_app() |
| 5 | if __name__ == '__main__': | 5 | if __name__ == '__main__': |
| 6 | - app.run(host="0.0.0.0", port="8840", threaded=True, debug=True) | ||
| 7 | - | 6 | + app.run(host="0.0.0.0", port="8840", threaded=True, debug=True) |
请
注册
或
登录
后发表评论