正在显示
18 个修改的文件
包含
1436 行增加
和
677 行删除
DMapManager @ 8e446e18
1 | -Subproject commit 8e446e18a7a81ea282d05f6026f4d41d5dae1378 |
1 | -import decimal | |
2 | - | |
3 | -from flask import Flask as _Flask | |
4 | -from flask.json import JSONEncoder as _JSONEncoder | |
5 | -from flask_cors import CORS | |
6 | -import time | |
7 | -import configure | |
8 | -from app.util import BlueprintApi | |
9 | -from app.util import find_class | |
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 | |
13 | -# from rtree import index | |
14 | -import logging | |
15 | -from sqlalchemy.orm import Session | |
16 | -import multiprocessing | |
17 | -from app.util.component.EntryData import EntryData | |
18 | -from app.util.component.EntryDataVacuate import EntryDataVacuate | |
19 | -import json | |
20 | -import threading | |
21 | -import traceback | |
22 | -from sqlalchemy import distinct | |
23 | -import uuid | |
24 | -from osgeo.ogr import DataSource | |
25 | -import datetime | |
26 | -from sqlalchemy import or_ | |
27 | -from app.util.component.StructuredPrint import StructurePrint | |
28 | -from app.util.component.PGUtil import PGUtil | |
29 | -import os | |
30 | - | |
31 | -class JSONEncoder(_JSONEncoder): | |
32 | - """ | |
33 | - 因为decimal不能序列化,增加Flask对decimal类的解析 | |
34 | - """ | |
35 | - def default(self, o): | |
36 | - if isinstance(o, decimal.Decimal): | |
37 | - return float(o) | |
38 | - super(JSONEncoder, self).default(o) | |
39 | - | |
40 | - | |
41 | -class Flask(_Flask): | |
42 | - json_encoder = JSONEncoder | |
43 | - | |
44 | - | |
45 | -GLOBAL_DIC={} | |
46 | -def create_app(): | |
47 | - """ | |
48 | - flask应用创建函数 | |
49 | - :return:app,flask实例 | |
50 | - """ | |
51 | - | |
52 | - # app基本设置 | |
53 | - app = Flask(__name__) | |
54 | - app.config['SQLALCHEMY_DATABASE_URI'] = configure.SQLALCHEMY_DATABASE_URI | |
55 | - app.config['echo'] = True | |
56 | - app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True | |
57 | - app.config['JSON_AS_ASCII'] = False | |
58 | - app.config['SECRET_KEY'] = configure.SECRET_KEY | |
59 | - app.config['OAUTH2_JWT_ENABLED'] = True | |
60 | - | |
61 | - app.config['OAUTH2_JWT_ISS'] = 'http://localhost:5000' | |
62 | - app.config['OAUTH2_JWT_KEY'] = 'secret-key' | |
63 | - app.config['OAUTH2_JWT_ALG'] = 'HS256' | |
64 | - # app.config['SQLALCHEMY_ECHO'] = True | |
65 | - | |
66 | - # 跨域设置 | |
67 | - CORS(app) | |
68 | - | |
69 | - # swagger设置 | |
70 | - swagger_config = Swagger.DEFAULT_CONFIG | |
71 | - swagger_config.update(configure.swagger_configure) | |
72 | - Swagger(app, config=swagger_config) | |
73 | - | |
74 | - # 创建数据库 | |
75 | - db.init_app(app) | |
76 | - db.create_all(app=app) | |
77 | - | |
78 | - # 日志 | |
79 | - logging.basicConfig(level=logging.INFO) | |
80 | - log_file = os.path.join(os.path.dirname(os.path.dirname( | |
81 | - os.path.realpath(__file__))), "logs", "log.txt") | |
82 | - handler = logging.FileHandler( | |
83 | - log_file, encoding='UTF-8') # 设置日志字符集和存储路径名字 | |
84 | - logging_format = logging.Formatter( | |
85 | - '[%(levelname)s] %(asctime)s %(message)s') | |
86 | - handler.setFormatter(logging_format) | |
87 | - app.logger.addHandler(handler) | |
88 | - | |
89 | - # 配置使用鉴权组件,不写无法认证授权 | |
90 | - config_oauth(app) | |
91 | - | |
92 | - # 注册blueprint,查找BlueprintApi的子类 | |
93 | - for scan in configure.scan_module: | |
94 | - for api in find_class(scan, BlueprintApi): | |
95 | - app.register_blueprint(api.bp) | |
96 | - | |
97 | - # 入库监测线程 | |
98 | - | |
99 | - @app.before_first_request | |
100 | - def data_entry_process(): | |
101 | - StructurePrint.print("start listen") | |
102 | - process = threading.Thread(target=data_entry_center) | |
103 | - process.start() | |
104 | - | |
105 | - # 不检测https | |
106 | - os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' | |
107 | - | |
108 | - # 上下文全局变量字典 | |
109 | - global GLOBAL_DIC | |
110 | - | |
111 | - return app | |
112 | - | |
113 | - | |
114 | -def data_entry_center(): | |
115 | - running_dict = {} | |
116 | - sys_session: Session = PGUtil.get_db_session( | |
117 | - configure.SQLALCHEMY_DATABASE_URI) | |
118 | - | |
119 | - while True: | |
120 | - | |
121 | - try: | |
122 | - time.sleep(3) | |
123 | - | |
124 | - # 已经结束的进程 从监测中删除 | |
125 | - remove_process = [] | |
126 | - | |
127 | - # structured_print(running_dict.__len__().__str__()) | |
128 | - | |
129 | - for process, layer_names in running_dict.items(): | |
130 | - if not process.is_alive(): | |
131 | - for l in layer_names: | |
132 | - inserted = sys_session.query( | |
133 | - InsertingLayerName).filter_by(name=l).one_or_none() | |
134 | - if inserted: | |
135 | - sys_session.delete(inserted) | |
136 | - sys_session.commit() | |
137 | - remove_process.append(process) | |
138 | - for process in remove_process: | |
139 | - running_dict.pop(process) | |
140 | - | |
141 | - # StructurePrint.print("listening...") | |
142 | - | |
143 | - # 入库进程少于阈值,开启入库进程 | |
144 | - | |
145 | - inter_size = sys_session.query( | |
146 | - distinct(InsertingLayerName.task_guid)).count() | |
147 | - | |
148 | - if inter_size < configure.entry_data_thread: | |
149 | - # 锁表啊 | |
150 | - ready_task:Task = sys_session.query(Task).filter_by(state=0,task_type=1).order_by(Task.create_time).with_lockmode("update").limit(1).one_or_none() | |
151 | - if ready_task: | |
152 | - | |
153 | - try: | |
154 | - parameter = json.loads(ready_task.parameter) | |
155 | - StructurePrint.print("检测到入库任务") | |
156 | - ready_task.state = 2 | |
157 | - ready_task.process = "入库中" | |
158 | - sys_session.commit() | |
159 | - | |
160 | - metas: list = json.loads( | |
161 | - parameter.get("meta").__str__()) | |
162 | - parameter["meta"] = metas | |
163 | - | |
164 | - database = sys_session.query(Database).filter_by( | |
165 | - guid=ready_task.database_guid).one_or_none() | |
166 | - pg_ds: DataSource = PGUtil.open_pg_data_source( | |
167 | - 1, DES.decode(database.sqlalchemy_uri)) | |
168 | - | |
169 | - this_task_layer = [] | |
170 | - for meta in metas: | |
171 | - overwrite = parameter.get("overwrite", "no") | |
172 | - | |
173 | - for layer_name_origin, layer_name in meta.get("layer").items(): | |
174 | - origin_name = layer_name | |
175 | - no = 1 | |
176 | - | |
177 | - while (overwrite.__eq__("no") and pg_ds.GetLayerByName(layer_name)) or sys_session.query(InsertingLayerName).filter_by(name=layer_name).one_or_none(): | |
178 | - layer_name = origin_name + "_{}".format(no) | |
179 | - no += 1 | |
180 | - | |
181 | - # 添加到正在入库的列表中 | |
182 | - iln = InsertingLayerName(guid=uuid.uuid1().__str__(), | |
183 | - task_guid=ready_task.guid, | |
184 | - name=layer_name) | |
185 | - | |
186 | - sys_session.add(iln) | |
187 | - sys_session.commit() | |
188 | - this_task_layer.append(layer_name) | |
189 | - # 修改表名 | |
190 | - meta["layer"][layer_name_origin] = layer_name | |
191 | - | |
192 | - pg_ds.Destroy() | |
193 | - entry_data_process = multiprocessing.Process( | |
194 | - target=EntryDataVacuate().entry, args=(parameter,)) | |
195 | - entry_data_process.start() | |
196 | - running_dict[entry_data_process] = this_task_layer | |
197 | - except Exception as e: | |
198 | - sys_session.query(Task).filter_by(guid=ready_task.guid).update( | |
199 | - {"state": -1, "process": "入库失败"}) | |
200 | - sys_session.commit() | |
201 | - StructurePrint.print(e.__str__(), "error") | |
202 | - else: | |
203 | - # 解表啊 | |
204 | - sys_session.commit() | |
205 | - except Exception as e: | |
206 | - sys_session.commit() | |
207 | - StructurePrint.print(e.__str__(), "error") | |
1 | +import decimal | |
2 | + | |
3 | +from flask import Flask as _Flask | |
4 | +from flask.json import JSONEncoder as _JSONEncoder | |
5 | +from flask_cors import CORS | |
6 | +import time | |
7 | + | |
8 | +from sqlalchemy.sql.expression import true | |
9 | +import configure | |
10 | +from app.util import BlueprintApi | |
11 | +from app.util import find_class | |
12 | +from app.models import db, Table, InsertingLayerName, Database, DES, Task | |
13 | +from app.modules.auth.oauth2 import config_oauth, myCodeIDToken | |
14 | +from flasgger import Swagger | |
15 | +# from rtree import index | |
16 | +import logging | |
17 | +from sqlalchemy.orm import Session | |
18 | +import multiprocessing | |
19 | +from app.util.component.EntryData import EntryData | |
20 | +from app.util.component.EntryDataVacuate import EntryDataVacuate | |
21 | +import json | |
22 | +import threading | |
23 | +import traceback | |
24 | +from sqlalchemy import distinct | |
25 | +import uuid | |
26 | +from osgeo.ogr import DataSource | |
27 | +import datetime | |
28 | +from sqlalchemy import or_ | |
29 | +from app.util.component.StructuredPrint import StructurePrint | |
30 | +from app.util.component.PGUtil import PGUtil | |
31 | +import os | |
32 | + | |
33 | + | |
34 | +class JSONEncoder(_JSONEncoder): | |
35 | + """ | |
36 | + 因为decimal不能序列化,增加Flask对decimal类的解析 | |
37 | + """ | |
38 | + | |
39 | + def default(self, o): | |
40 | + if isinstance(o, decimal.Decimal): | |
41 | + return float(o) | |
42 | + super(JSONEncoder, self).default(o) | |
43 | + | |
44 | + | |
45 | +class Flask(_Flask): | |
46 | + json_encoder = JSONEncoder | |
47 | + | |
48 | + | |
49 | +GLOBAL_DIC = {} | |
50 | + | |
51 | + | |
52 | +def create_app(): | |
53 | + """ | |
54 | + flask应用创建函数 | |
55 | + :return:app,flask实例 | |
56 | + """ | |
57 | + | |
58 | + # app基本设置 | |
59 | + app = Flask(__name__) | |
60 | + app.config['SQLALCHEMY_DATABASE_URI'] = configure.SQLALCHEMY_DATABASE_URI | |
61 | + app.config['echo'] = True | |
62 | + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True | |
63 | + app.config['JSON_AS_ASCII'] = False | |
64 | + app.config['SECRET_KEY'] = configure.SECRET_KEY | |
65 | + app.config['OAUTH2_JWT_ENABLED'] = True | |
66 | + | |
67 | + app.config['OAUTH2_JWT_ISS'] = 'http://localhost:5000' | |
68 | + app.config['OAUTH2_JWT_KEY'] = 'secret-key' | |
69 | + app.config['OAUTH2_JWT_ALG'] = 'HS256' | |
70 | + # app.config['SQLALCHEMY_ECHO'] = True | |
71 | + | |
72 | + # allows cookies and credentials to be submitted across domains | |
73 | + app.config['CORS_SUPPORTS_CREDENTIALS'] = true | |
74 | + app.config['CORS_ORIGINS ']="*" | |
75 | + | |
76 | + # 跨域设置 | |
77 | + CORS(app) | |
78 | + | |
79 | + # swagger设置 | |
80 | + swagger_config = Swagger.DEFAULT_CONFIG | |
81 | + swagger_config.update(configure.swagger_configure) | |
82 | + Swagger(app, config=swagger_config) | |
83 | + | |
84 | + # 创建数据库 | |
85 | + db.init_app(app) | |
86 | + db.create_all(app=app) | |
87 | + | |
88 | + # 日志 | |
89 | + logging.basicConfig(level=logging.INFO) | |
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') | |
96 | + handler.setFormatter(logging_format) | |
97 | + app.logger.addHandler(handler) | |
98 | + | |
99 | + # 配置使用鉴权组件,不写无法认证授权 | |
100 | + config_oauth(app) | |
101 | + | |
102 | + # 注册blueprint,查找BlueprintApi的子类 | |
103 | + for scan in configure.scan_module: | |
104 | + for api in find_class(scan, BlueprintApi): | |
105 | + app.register_blueprint(api.bp) | |
106 | + | |
107 | + # 入库监测线程 | |
108 | + | |
109 | + @app.before_first_request | |
110 | + def data_entry_process(): | |
111 | + StructurePrint.print("start listen") | |
112 | + process = threading.Thread(target=data_entry_center) | |
113 | + process.start() | |
114 | + | |
115 | + # 不检测https | |
116 | + os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' | |
117 | + | |
118 | + # 上下文全局变量字典 | |
119 | + global GLOBAL_DIC | |
120 | + | |
121 | + return app | |
122 | + | |
123 | + | |
124 | +def data_entry_center(): | |
125 | + running_dict = {} | |
126 | + sys_session: Session = PGUtil.get_db_session( | |
127 | + configure.SQLALCHEMY_DATABASE_URI) | |
128 | + | |
129 | + while True: | |
130 | + | |
131 | + try: | |
132 | + time.sleep(3) | |
133 | + | |
134 | + # 已经结束的进程 从监测中删除 | |
135 | + remove_process = [] | |
136 | + | |
137 | + # structured_print(running_dict.__len__().__str__()) | |
138 | + | |
139 | + for process, layer_names in running_dict.items(): | |
140 | + if not process.is_alive(): | |
141 | + for l in layer_names: | |
142 | + inserted = sys_session.query( | |
143 | + InsertingLayerName).filter_by(name=l).one_or_none() | |
144 | + if inserted: | |
145 | + sys_session.delete(inserted) | |
146 | + sys_session.commit() | |
147 | + remove_process.append(process) | |
148 | + for process in remove_process: | |
149 | + running_dict.pop(process) | |
150 | + | |
151 | + # StructurePrint.print("listening...") | |
152 | + | |
153 | + # 入库进程少于阈值,开启入库进程 | |
154 | + | |
155 | + inter_size = sys_session.query( | |
156 | + distinct(InsertingLayerName.task_guid)).count() | |
157 | + | |
158 | + if inter_size < configure.entry_data_thread: | |
159 | + # 锁表啊 | |
160 | + ready_task: Task = sys_session.query(Task).filter_by(state=0, task_type=1).order_by( | |
161 | + Task.create_time).with_lockmode("update").limit(1).one_or_none() | |
162 | + if ready_task: | |
163 | + | |
164 | + try: | |
165 | + parameter = json.loads(ready_task.parameter) | |
166 | + StructurePrint.print("检测到入库任务") | |
167 | + ready_task.state = 2 | |
168 | + ready_task.process = "入库中" | |
169 | + sys_session.commit() | |
170 | + | |
171 | + metas: list = json.loads( | |
172 | + parameter.get("meta").__str__()) | |
173 | + parameter["meta"] = metas | |
174 | + | |
175 | + database = sys_session.query(Database).filter_by( | |
176 | + guid=ready_task.database_guid).one_or_none() | |
177 | + pg_ds: DataSource = PGUtil.open_pg_data_source( | |
178 | + 1, DES.decode(database.sqlalchemy_uri)) | |
179 | + | |
180 | + this_task_layer = [] | |
181 | + for meta in metas: | |
182 | + overwrite = parameter.get("overwrite", "no") | |
183 | + | |
184 | + for layer_name_origin, layer_name in meta.get("layer").items(): | |
185 | + origin_name = layer_name | |
186 | + no = 1 | |
187 | + | |
188 | + while (overwrite.__eq__("no") and pg_ds.GetLayerByName(layer_name)) or sys_session.query(InsertingLayerName).filter_by(name=layer_name).one_or_none(): | |
189 | + layer_name = origin_name + "_{}".format(no) | |
190 | + no += 1 | |
191 | + | |
192 | + # 添加到正在入库的列表中 | |
193 | + iln = InsertingLayerName(guid=uuid.uuid1().__str__(), | |
194 | + task_guid=ready_task.guid, | |
195 | + name=layer_name) | |
196 | + | |
197 | + sys_session.add(iln) | |
198 | + sys_session.commit() | |
199 | + this_task_layer.append(layer_name) | |
200 | + # 修改表名 | |
201 | + meta["layer"][layer_name_origin] = layer_name | |
202 | + | |
203 | + pg_ds.Destroy() | |
204 | + entry_data_process = multiprocessing.Process( | |
205 | + target=EntryDataVacuate().entry, args=(parameter,)) | |
206 | + entry_data_process.start() | |
207 | + running_dict[entry_data_process] = this_task_layer | |
208 | + except Exception as e: | |
209 | + sys_session.query(Task).filter_by(guid=ready_task.guid).update( | |
210 | + {"state": -1, "process": "入库失败"}) | |
211 | + sys_session.commit() | |
212 | + StructurePrint.print(e.__str__(), "error") | |
213 | + else: | |
214 | + # 解表啊 | |
215 | + sys_session.commit() | |
216 | + except Exception as e: | |
217 | + sys_session.commit() | |
218 | + StructurePrint.print(e.__str__(), "error") | |
\ No newline at end of file | ... | ... |
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 flask_sqlalchemy import sqlalchemy | |
5 | -from sqlalchemy import and_ | |
6 | -from .models import * | |
7 | -from werkzeug.security import gen_salt | |
8 | -import time | |
9 | -from .oauth2 import authorization, require_oauth, generate_user_info | |
10 | -from authlib.oauth2 import OAuth2Error | |
11 | -from authlib.integrations.flask_oauth2 import current_token | |
12 | - | |
13 | - | |
14 | -def current_user(): | |
15 | - if 'id' in session: | |
16 | - uid = session['id'] | |
17 | - return User.query.get(uid) | |
18 | - return None | |
19 | - | |
20 | - | |
21 | -def split_by_crlf(s): | |
22 | - return [v for v in s.splitlines() if v] | |
23 | - | |
24 | - | |
25 | -class DataManager(BlueprintApi): | |
26 | - bp = Blueprint("Auth", __name__, url_prefix="/auth") | |
27 | - | |
28 | - # @staticmethod | |
29 | - # @bp.route('/test', methods=('GET', 'POST')) | |
30 | - # def Test(): | |
31 | - # res = {} | |
32 | - # try: | |
33 | - # res['user'] = User.query.all() | |
34 | - # except Exception as e: | |
35 | - # raise e | |
36 | - # return res | |
37 | - | |
38 | - # @staticmethod | |
39 | - # @bp.route('/login', methods=('GET', 'POST')) | |
40 | - # def Login(): | |
41 | - # if request.method == 'POST': | |
42 | - # username = request.form['username'] | |
43 | - # password = request.form['password'] | |
44 | - # user = User.query.filter_by(username=username).first() | |
45 | - # if not user: | |
46 | - # user = User(username=username, | |
47 | - # password=password, role='admin') | |
48 | - # db.session.add(user) | |
49 | - # db.session.commit() | |
50 | - # session['id'] = user.id | |
51 | - # return redirect('/auth/authorize') | |
52 | - # user = current_user() | |
53 | - # if user: | |
54 | - # clients = OAuth2Client.query.filter_by(user_id=user.id).all() | |
55 | - # else: | |
56 | - # clients = [] | |
57 | - # return render_template('auth/authorize.html', user=user, clients=clients) | |
58 | - | |
59 | - # @staticmethod | |
60 | - # @bp.route('/create_client', methods=('GET', 'POST')) | |
61 | - # def create_client(): | |
62 | - # user = current_user() | |
63 | - # if not user: | |
64 | - # return redirect('/auth/login') | |
65 | - # if request.method == 'GET': | |
66 | - # return render_template('auth/create_client.html') | |
67 | - # form = request.form | |
68 | - # client_id = gen_salt(24) | |
69 | - # client = OAuth2Client(client_id=client_id, user_id=user.id) | |
70 | - # # Mixin doesn't set the issue_at date | |
71 | - # client.client_id_issued_at = int(time.time()) | |
72 | - # if client.token_endpoint_auth_method == 'none': | |
73 | - # client.client_secret = '' | |
74 | - # else: | |
75 | - # client.client_secret = gen_salt(48) | |
76 | - # client_metadata = { | |
77 | - # "client_name": form["client_name"], | |
78 | - # "client_uri": form["client_uri"], | |
79 | - # "grant_types": split_by_crlf(form["grant_type"]), | |
80 | - # "redirect_uris": split_by_crlf(form["redirect_uri"]), | |
81 | - # "response_types": split_by_crlf(form["response_type"]), | |
82 | - # "scope": form["scope"], | |
83 | - # "token_endpoint_auth_method": form["token_endpoint_auth_method"] | |
84 | - # } | |
85 | - # client.set_client_metadata(client_metadata) | |
86 | - # db.session.add(client) | |
87 | - # db.session.commit() | |
88 | - # return redirect('/auth/login') | |
89 | - | |
90 | - @staticmethod | |
91 | - @bp.route('/authorize', methods=('GET', 'POST')) | |
92 | - def authorize(): | |
93 | - user = current_user() | |
94 | - if request.method == 'GET': | |
95 | - try: | |
96 | - grant = authorization.validate_consent_request(end_user=user) | |
97 | - except OAuth2Error as error: | |
98 | - return jsonify(dict(error.get_body())) | |
99 | - return render_template('auth/authorize.html', user=user, grant=grant) | |
100 | - # return render_template('auth/login1.html', user=user, grant=grant) | |
101 | - if not user and 'username' in request.form: | |
102 | - username = request.form.get('username') | |
103 | - password = request.form.get('password') | |
104 | - user = User.query.filter_by( | |
105 | - username=username, password=password).first() | |
106 | - grant_user = user | |
107 | - # if request.form['confirm']: | |
108 | - # grant_user = user | |
109 | - # else: | |
110 | - # grant_user = None | |
111 | - return authorization.create_authorization_response(grant_user=grant_user) | |
112 | - | |
113 | - @staticmethod | |
114 | - @bp.route('/token', methods=['POST']) | |
115 | - def issue_token(): | |
116 | - return authorization.create_token_response() | |
117 | - | |
118 | - @staticmethod | |
119 | - @bp.route('/userinfo') | |
120 | - @require_oauth('profile') | |
121 | - def api_me(): | |
122 | - return jsonify(generate_user_info(current_token.user, current_token.scope)) | |
1 | +from enum import auto | |
2 | +from logging import error | |
3 | +from flasgger import swag_from | |
4 | +from app.util import BlueprintApi | |
5 | +from app.util import BlueprintApi | |
6 | +from flask import Blueprint, render_template, redirect, request, session, jsonify | |
7 | +from sqlalchemy import and_ | |
8 | +from .models import * | |
9 | +from .oauth2 import authorization, require_oauth, generate_user_info | |
10 | +from authlib.oauth2 import OAuth2Error | |
11 | +from authlib.integrations.flask_oauth2 import current_token | |
12 | +from . import user_create, client_create, client_query, user_query, user_update, user_delete | |
13 | + | |
14 | + | |
15 | +def current_user(): | |
16 | + if "id" in session: | |
17 | + uid = session["id"] | |
18 | + return User.query.get(uid) | |
19 | + return None | |
20 | + | |
21 | + | |
22 | +def remove_user(): | |
23 | + user = current_user() | |
24 | + if user: | |
25 | + session.pop("id") | |
26 | + | |
27 | + | |
28 | +def split_by_crlf(s): | |
29 | + return [v for v in s.splitlines() if v] | |
30 | + | |
31 | + | |
32 | +class DataManager(BlueprintApi): | |
33 | + bp = Blueprint("Auth", __name__, url_prefix="/auth") | |
34 | + | |
35 | + # @staticmethod | |
36 | + # @bp.route("/test", methods=("GET", "POST")) | |
37 | + # def Test(): | |
38 | + # res = {} | |
39 | + # try: | |
40 | + # res["user"] = User.query.all() | |
41 | + # except Exception as e: | |
42 | + # raise e | |
43 | + # return res | |
44 | + | |
45 | + # @staticmethod | |
46 | + # @bp.route("/login", methods=("GET", "POST")) | |
47 | + # def Login(): | |
48 | + # if request.method == "POST": | |
49 | + # username = request.form["username"] | |
50 | + # password = request.form["password"] | |
51 | + # user = User.query.filter_by(username=username).first() | |
52 | + # if not user: | |
53 | + # user = User(username=username, | |
54 | + # password=password, role="admin") | |
55 | + # db.session.add(user) | |
56 | + # db.session.commit() | |
57 | + # session["id"] = user.id | |
58 | + # return redirect("/auth/authorize") | |
59 | + # user = current_user() | |
60 | + # if user: | |
61 | + # clients = OAuth2Client.query.filter_by(user_id=user.id).all() | |
62 | + # else: | |
63 | + # clients = [] | |
64 | + # return render_template("auth/authorize.html", user=user, clients=clients) | |
65 | + | |
66 | + # @staticmethod | |
67 | + # @bp.route("/create_client", methods=("GET", "POST")) | |
68 | + # def create_client(): | |
69 | + # user = current_user() | |
70 | + # if not user: | |
71 | + # return redirect("/auth/login") | |
72 | + # if request.method == "GET": | |
73 | + # return render_template("auth/create_client.html") | |
74 | + # form = request.form | |
75 | + # client_id = gen_salt(24) | |
76 | + # client = OAuth2Client(client_id=client_id, user_id=user.id) | |
77 | + # # Mixin doesn"t set the issue_at date | |
78 | + # client.client_id_issued_at = int(time.time()) | |
79 | + # if client.token_endpoint_auth_method == "none": | |
80 | + # client.client_secret = "" | |
81 | + # else: | |
82 | + # client.client_secret = gen_salt(48) | |
83 | + # client_metadata = { | |
84 | + # "client_name": form["client_name"], | |
85 | + # "client_uri": form["client_uri"], | |
86 | + # "grant_types": split_by_crlf(form["grant_type"]), | |
87 | + # "redirect_uris": split_by_crlf(form["redirect_uri"]), | |
88 | + # "response_types": split_by_crlf(form["response_type"]), | |
89 | + # "scope": form["scope"], | |
90 | + # "token_endpoint_auth_method": form["token_endpoint_auth_method"] | |
91 | + # } | |
92 | + # client.set_client_metadata(client_metadata) | |
93 | + # db.session.add(client) | |
94 | + # db.session.commit() | |
95 | + # return redirect("/auth/login") | |
96 | + | |
97 | + @staticmethod | |
98 | + @bp.route("/authorize", methods=("GET", "POST")) | |
99 | + def authorize(): | |
100 | + user = current_user() | |
101 | + if request.method == "GET": | |
102 | + # 没有登录,跳转到登录界面 | |
103 | + try: | |
104 | + grant = authorization.validate_consent_request(end_user=user) | |
105 | + except OAuth2Error as error: | |
106 | + return jsonify(dict(error.get_body())) | |
107 | + if not user: | |
108 | + return render_template("auth/authorize.html", user=user, grant=grant) | |
109 | + # return render_template("auth/login1.html", user=user, grant=grant) | |
110 | + error = "" | |
111 | + if not user: | |
112 | + if not "username" in request.form or not request.form.get("username"): | |
113 | + error = "用户名不可为空" | |
114 | + elif not "password" in request.form or not request.form.get("password"): | |
115 | + error = "密码不可为空" | |
116 | + else: | |
117 | + username = request.form.get("username") | |
118 | + password = request.form.get("password") | |
119 | + user = User.query.filter_by( | |
120 | + username=username, password=password).first() | |
121 | + if not user: | |
122 | + error = "账号或密码不正确" | |
123 | + | |
124 | + if user: | |
125 | + session["id"] = user.id | |
126 | + grant_user = user | |
127 | + return authorization.create_authorization_response(grant_user=grant_user) | |
128 | + | |
129 | + try: | |
130 | + grant = authorization.validate_consent_request(end_user=user) | |
131 | + except OAuth2Error as error: | |
132 | + return jsonify(dict(error.get_body())) | |
133 | + return render_template("auth/authorize.html", user=user, grant=grant, error=error) | |
134 | + | |
135 | + # if request.form["confirm"]: | |
136 | + # grant_user = user | |
137 | + # else: | |
138 | + # grant_user = None | |
139 | + | |
140 | + @staticmethod | |
141 | + @bp.route("/token", methods=["POST"]) | |
142 | + def issue_token(): | |
143 | + return authorization.create_token_response() | |
144 | + | |
145 | + @staticmethod | |
146 | + @bp.route("/userinfo") | |
147 | + @require_oauth("profile") | |
148 | + def api_me(): | |
149 | + try: | |
150 | + return jsonify(generate_user_info(current_token.user, current_token.scope)) | |
151 | + except error as e: | |
152 | + return jsonify(dict(e.get_body())) | |
153 | + | |
154 | + @staticmethod | |
155 | + @bp.route("/logout", methods=["GET"]) | |
156 | + # @require_oauth("profile") | |
157 | + def logout(): | |
158 | + url = '' | |
159 | + try: | |
160 | + user = current_user() | |
161 | + grant = authorization.validate_consent_request(end_user=user) | |
162 | + access_token = request.args.get("accesstoken") | |
163 | + accesstoken = OAuth2Token.query.filter_by( | |
164 | + access_token=access_token).first() | |
165 | + accesstoken.revoked = True | |
166 | + db.session.commit() | |
167 | + remove_user() | |
168 | + if accesstoken: | |
169 | + url = grant.client.client_uri | |
170 | + except OAuth2Error as error: | |
171 | + return jsonify(dict(error.get_body())) | |
172 | + return redirect(url) | |
173 | + # if current_token: | |
174 | + # remove_user() | |
175 | + # # accesstoken = OAuth2Token.query.filter_by( | |
176 | + # # access_token=current_token.access_token).first() | |
177 | + # try: | |
178 | + # # accesstoken.revoked = True | |
179 | + # # db.session.commit() | |
180 | + # except error as e: | |
181 | + # return jsonify(dict(e.get_body())) | |
182 | + # else: | |
183 | + # return jsonify({"result": False, "message": "access_token is null"}) | |
184 | + | |
185 | + # return jsonify({"result": True, "message": "logout success"}) | |
186 | + | |
187 | + """接口""" | |
188 | + @staticmethod | |
189 | + @bp.route("/users", methods=["GET"]) | |
190 | + @swag_from(user_query.Api.api_doc) | |
191 | + def user_query(): | |
192 | + """ | |
193 | + 获取用户列表 | |
194 | + """ | |
195 | + return user_query.Api().result | |
196 | + | |
197 | + @staticmethod | |
198 | + @bp.route("/users", methods=["POST"]) | |
199 | + @swag_from(user_create.Api.api_doc) | |
200 | + def user_create(): | |
201 | + """ | |
202 | + 创建用户 | |
203 | + """ | |
204 | + return user_create.Api().result | |
205 | + | |
206 | + @staticmethod | |
207 | + @bp.route("/userEdit", methods=["POST"]) | |
208 | + @swag_from(user_update.Api.api_doc) | |
209 | + def user_update(): | |
210 | + """ | |
211 | + 更新用户信息 | |
212 | + """ | |
213 | + return user_update.Api().result | |
214 | + | |
215 | + @staticmethod | |
216 | + @bp.route("/userDelete", methods=["POST"]) | |
217 | + @swag_from(user_delete.Api.api_doc) | |
218 | + def user_delete(): | |
219 | + """ | |
220 | + 删除用户 | |
221 | + """ | |
222 | + return user_delete.Api().result | |
223 | + | |
224 | + @staticmethod | |
225 | + @bp.route("/client", methods=["POST"]) | |
226 | + @swag_from(client_create.Api.api_doc) | |
227 | + def client_create(): | |
228 | + """ | |
229 | + 创建client | |
230 | + """ | |
231 | + return client_create.Api().result | |
232 | + | |
233 | + @staticmethod | |
234 | + @bp.route("/client", methods=["GET"]) | |
235 | + @swag_from(client_query.Api.api_doc) | |
236 | + def client_query(): | |
237 | + """ | |
238 | + 获取client列表 | |
239 | + """ | |
240 | + return client_query.Api().result | ... | ... |
app/modules/auth/client_create.py
0 → 100644
1 | +# coding=utf-8 | |
2 | +#author: qianyingz | |
3 | +#createtime: 2021/8/13 | |
4 | +#email: qianyingz@chinadci.com | |
5 | + | |
6 | +from re import split | |
7 | +from .models import * | |
8 | +from app.util.component.ApiTemplate import ApiTemplate | |
9 | +from werkzeug.security import gen_salt | |
10 | +import time | |
11 | +import string | |
12 | + | |
13 | + | |
14 | +class Api(ApiTemplate): | |
15 | + api_name = "注册客户端" | |
16 | + | |
17 | + def para_check(self): | |
18 | + if not self.para.get("name"): | |
19 | + raise Exception("name is null") | |
20 | + if not self.para.get("uri"): | |
21 | + raise Exception("uri is null") | |
22 | + if not self.para.get("redirect_uris"): | |
23 | + raise Exception("redirect_uris is null") | |
24 | + # if not self.para.get('username'): | |
25 | + # raise Exception("username is null") | |
26 | + # if not self.para.get("scope"): | |
27 | + # raise Exception("scope is null") | |
28 | + # if not self.para.get("grant_type"): | |
29 | + # raise Exception("grant_type is null") | |
30 | + # if not self.para.get("response_type"): | |
31 | + # raise Exception("response_type is null") | |
32 | + | |
33 | + def process(self): | |
34 | + | |
35 | + # 返回结果 | |
36 | + res = {} | |
37 | + res["result"] = False | |
38 | + try: | |
39 | + # 默认值 | |
40 | + scope = "openid profile" | |
41 | + grant_type = ["authorization_code"] | |
42 | + response_type = ["code"] | |
43 | + auth_method = "client_secret_basic" | |
44 | + # 业务逻辑 | |
45 | + username = self.para.get("username") | |
46 | + client_id = gen_salt(24) | |
47 | + name = self.para.get("name") | |
48 | + uri = self.para.get("uri") | |
49 | + redirect_uris = self.para.get("redirect_uris").split(",") | |
50 | + | |
51 | + if not username: | |
52 | + username = 'admin' | |
53 | + user = User.query.filter_by(username=username).first() | |
54 | + if not User: | |
55 | + res["msg"] = "username 指定用户不存在" | |
56 | + res["data"] = {} | |
57 | + res["result"] = False | |
58 | + else: | |
59 | + client = OAuth2Client(client_id=client_id, user_id=user.id) | |
60 | + # Mixin doesn"t set the issue_at date | |
61 | + client.client_id_issued_at = int(time.time()) | |
62 | + if client.token_endpoint_auth_method == "none": | |
63 | + client.client_secret = "" | |
64 | + else: | |
65 | + client.client_secret = gen_salt(48) | |
66 | + client_metadata = { | |
67 | + "client_name": name, | |
68 | + "client_uri": uri, | |
69 | + "grant_types": grant_type, | |
70 | + "redirect_uris": redirect_uris, | |
71 | + "response_types": response_type, | |
72 | + "scope": scope, | |
73 | + "token_endpoint_auth_method": auth_method | |
74 | + } | |
75 | + client.set_client_metadata(client_metadata) | |
76 | + db.session.add(client) | |
77 | + db.session.commit() | |
78 | + res["msg"] = "创建client成功" | |
79 | + res["data"] = {"client_secret": client.client_secret, | |
80 | + "client_id": client.client_id} | |
81 | + res["result"] = True | |
82 | + except Exception as e: | |
83 | + db.session.rollback() | |
84 | + raise e | |
85 | + return res | |
86 | + | |
87 | + api_doc = { | |
88 | + | |
89 | + "tags": ["认证接口"], | |
90 | + "parameters": [ | |
91 | + {"name": "name", | |
92 | + "in": "formData", | |
93 | + "type": "string", | |
94 | + "description": "客户端名称", | |
95 | + "required": "true"}, | |
96 | + {"name": "uri", | |
97 | + "in": "formData", | |
98 | + "type": "string", | |
99 | + "description": "客户端地址,多个地址用,连接", | |
100 | + "required": "true"}, | |
101 | + {"name": "redirect_uris", | |
102 | + "in": "formData", | |
103 | + "type": "string", | |
104 | + "description": "重定向地址", | |
105 | + "required": "true"}, | |
106 | + {"name": "username", | |
107 | + "in": "formData", | |
108 | + "type": "string", | |
109 | + "description": "注册client账号,默认使用admin" | |
110 | + }, | |
111 | + # {"name": "scope", | |
112 | + # "in": "formData", | |
113 | + # "type": "string", | |
114 | + # "description": "范围"}, | |
115 | + # {"name": "grant_type", | |
116 | + # "in": "formData", | |
117 | + # "type": "string", | |
118 | + # "description": "授权类型: authorization_code"}, | |
119 | + # {"name": "response_type", | |
120 | + # "in": "formData", | |
121 | + # "type": "string", | |
122 | + # "description": "授权类型: code"} | |
123 | + ], | |
124 | + "responses": { | |
125 | + 200: { | |
126 | + "schema": { | |
127 | + "properties": { | |
128 | + } | |
129 | + } | |
130 | + } | |
131 | + } | |
132 | + } | ... | ... |
app/modules/auth/client_query.py
0 → 100644
1 | +# coding=utf-8 | |
2 | +#author: qianyingz | |
3 | +#createtime: 2021/8/13 | |
4 | +#email: qianyingz@chinadci.com | |
5 | + | |
6 | +from .models import * | |
7 | +from app.util.component.ApiTemplate import ApiTemplate | |
8 | +from werkzeug.security import gen_salt | |
9 | + | |
10 | +class Api(ApiTemplate): | |
11 | + api_name = "获取client列表" | |
12 | + | |
13 | + def para_check(self): | |
14 | + pass | |
15 | + | |
16 | + def process(self): | |
17 | + # 返回结果 | |
18 | + res = {} | |
19 | + res["result"] = False | |
20 | + res["data"] = [] | |
21 | + try: | |
22 | + # 默认值 | |
23 | + name = self.para.get("name") | |
24 | + if name: | |
25 | + clients = OAuth2Client.query.filter_by(client_name=name).all() | |
26 | + else: | |
27 | + clients = OAuth2Client.query.all() | |
28 | + for client in clients: | |
29 | + res["data"].append( | |
30 | + {'client_id': client.client_id, | |
31 | + 'client_secret': client.client_secret, | |
32 | + 'client_id_issued_at': client.client_id_issued_at, | |
33 | + 'client_secret_expires_at': client.client_secret_expires_at, | |
34 | + 'client_metadata': client.client_metadata, | |
35 | + 'id': client.id, | |
36 | + 'user_id': client.user_id | |
37 | + }) | |
38 | + res["msg"] = "获取clients集合成功" | |
39 | + res["result"] = True | |
40 | + except Exception as e: | |
41 | + db.session.rollback() | |
42 | + raise e | |
43 | + return res | |
44 | + | |
45 | + api_doc = { | |
46 | + | |
47 | + "tags": ["认证接口"], | |
48 | + "parameters": [ | |
49 | + {"name": "name", | |
50 | + "in": "formData", | |
51 | + "type": "string", | |
52 | + "description": "客户端名称"} | |
53 | + ], | |
54 | + "responses": { | |
55 | + 200: { | |
56 | + "schema": { | |
57 | + "properties": { | |
58 | + } | |
59 | + } | |
60 | + } | |
61 | + } | |
62 | + } | ... | ... |
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') | |
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__ = 'dmdms_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__ = 'dmdms_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__ = 'dmdms_oauth2_token' | |
55 | + | |
56 | + id = Column(Integer, primary_key=True) | |
57 | + user_id = Column( | |
58 | + Integer, ForeignKey('dmdms_user.id', ondelete='CASCADE')) | |
59 | + # name = Column(Text) | |
60 | + user = relationship('User') | |
\ No newline at end of file | ... | ... |
1 | +from os import access, remove | |
2 | +from time import time | |
1 | 3 | from authlib.integrations.flask_oauth2 import ( |
2 | 4 | AuthorizationServer, ResourceProtector) |
3 | 5 | from authlib.integrations.sqla_oauth2 import ( |
... | ... | @@ -13,11 +15,12 @@ from authlib.oidc.core.grants import ( |
13 | 15 | OpenIDImplicitGrant as _OpenIDImplicitGrant, |
14 | 16 | OpenIDHybridGrant as _OpenIDHybridGrant, |
15 | 17 | ) |
16 | -from authlib.oidc.core import UserInfo | |
18 | +from authlib.oidc.core import UserInfo, CodeIDToken, IDToken | |
19 | +from sqlalchemy.sql.sqltypes import DateTime | |
17 | 20 | from werkzeug.security import gen_salt |
18 | 21 | from .models import db, User |
19 | 22 | from .models import OAuth2Client, OAuth2AuthorizationCode, OAuth2Token |
20 | - | |
23 | +from flask import g | |
21 | 24 | |
22 | 25 | DUMMY_JWT_CONFIG = { |
23 | 26 | 'key': 'secret-key', |
... | ... | @@ -26,6 +29,17 @@ DUMMY_JWT_CONFIG = { |
26 | 29 | 'exp': 7200, |
27 | 30 | } |
28 | 31 | |
32 | +class myCodeIDToken(CodeIDToken): | |
33 | + def validate(self, now, leeway): | |
34 | + return super().validate(now=now, leeway=leeway) | |
35 | + | |
36 | + def validate_exp(self, now, leeway): | |
37 | + return super().validate_exp(now, leeway) | |
38 | + | |
39 | + | |
40 | +def validate_token(accesstoken): | |
41 | + return IDToken.validate(self=accesstoken) | |
42 | + | |
29 | 43 | |
30 | 44 | def exists_nonce(nonce, req): |
31 | 45 | exists = OAuth2AuthorizationCode.query.filter_by( |
... | ... | @@ -119,11 +133,12 @@ def config_oauth(app): |
119 | 133 | app, |
120 | 134 | query_client=query_client, |
121 | 135 | save_token=save_token |
136 | + # fetch_token=fetch_token | |
122 | 137 | ) |
123 | 138 | |
124 | 139 | # support all openid grants |
125 | 140 | authorization.register_grant(AuthorizationCodeGrant, [ |
126 | - OpenIDCode(require_nonce=True), | |
141 | + OpenIDCode(require_nonce=True) | |
127 | 142 | ]) |
128 | 143 | authorization.register_grant(ImplicitGrant) |
129 | 144 | authorization.register_grant(HybridGrant) | ... | ... |
app/modules/auth/user_create.py
0 → 100644
1 | +# coding=utf-8 | |
2 | +#author: qianyingz | |
3 | +#createtime: 2021/8/13 | |
4 | +#email: qianyingz@chinadci.com | |
5 | + | |
6 | +from .models import * | |
7 | +from app.util.component.ApiTemplate import ApiTemplate | |
8 | +import time | |
9 | + | |
10 | + | |
11 | +class Api(ApiTemplate): | |
12 | + api_name = "创建用户" | |
13 | + | |
14 | + def para_check(self): | |
15 | + if not self.para.get("username"): | |
16 | + raise Exception("username is null") | |
17 | + if not self.para.get("pwd"): | |
18 | + raise Exception("pwd is null") | |
19 | + if not self.para.get("role"): | |
20 | + raise Exception("role is null") | |
21 | + | |
22 | + def process(self): | |
23 | + | |
24 | + # 返回结果 | |
25 | + res = {} | |
26 | + res["result"] = False | |
27 | + try: | |
28 | + # 业务逻辑 | |
29 | + username = self.para.get("username") | |
30 | + password = self.para.get("pwd") | |
31 | + role = self.para.get("role") | |
32 | + company = self.para.get("company", None) | |
33 | + position = self.para.get("position", None) | |
34 | + email = self.para.get("email", None) | |
35 | + phone = self.para.get("phone", None) | |
36 | + # 是否重名 | |
37 | + if(User.query.filter_by(username=username).one_or_none()): | |
38 | + res["msg"] = "username 已存在" | |
39 | + else: | |
40 | + user = User(username=username, password=password, role=role, | |
41 | + phone=phone, company=company, position=position, email=email, | |
42 | + create_time=time.strftime( | |
43 | + "%Y-%m-%d %H:%M:%S", time.localtime()), | |
44 | + update_time=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) | |
45 | + db.session.add(user) | |
46 | + db.session.commit() | |
47 | + res["msg"] = "用户创建成功" | |
48 | + res["data"] = {"id": user.id, | |
49 | + "username": user.username, "role": user.role} | |
50 | + res["result"] = True | |
51 | + except Exception as e: | |
52 | + db.session.rollback() | |
53 | + raise e | |
54 | + return res | |
55 | + | |
56 | + api_doc = { | |
57 | + | |
58 | + "tags": ["认证接口"], | |
59 | + "parameters": [ | |
60 | + {"name": "username", | |
61 | + "in": "formData", | |
62 | + "type": "string", | |
63 | + "description": "用户名", | |
64 | + "required": "true"}, | |
65 | + {"name": "pwd", | |
66 | + "in": "formData", | |
67 | + "type": "string", | |
68 | + "description": "密码", | |
69 | + "required": "true"}, | |
70 | + {"name": "role", | |
71 | + "in": "formData", | |
72 | + "type": "string", | |
73 | + "description": "角色", | |
74 | + "required": "true"}, | |
75 | + {"name": "company", | |
76 | + "in": "formData", | |
77 | + "type": "string", | |
78 | + "description": "单位", | |
79 | + "required": ""}, | |
80 | + {"name": "email", | |
81 | + "in": "formData", | |
82 | + "type": "string", | |
83 | + "description": "邮件", | |
84 | + "required": ""}, | |
85 | + {"name": "phone", | |
86 | + "in": "formData", | |
87 | + "type": "string", | |
88 | + "description": "电话", | |
89 | + "required": ""}, | |
90 | + {"name": "position", | |
91 | + "in": "formData", | |
92 | + "type": "string", | |
93 | + "description": "职位", | |
94 | + "required": ""}, | |
95 | + ], | |
96 | + "responses": { | |
97 | + 200: { | |
98 | + "schema": { | |
99 | + "properties": { | |
100 | + } | |
101 | + } | |
102 | + } | |
103 | + } | |
104 | + } | ... | ... |
app/modules/auth/user_delete.py
0 → 100644
1 | +from app.util.component.ApiTemplate import ApiTemplate | |
2 | +import time | |
3 | +from .models import * | |
4 | + | |
5 | + | |
6 | +class Api(ApiTemplate): | |
7 | + api_name = "更新用户信息" | |
8 | + | |
9 | + def para_check(self): | |
10 | + if not self.para.get("guid"): | |
11 | + raise Exception("guid is null") | |
12 | + return super().para_check() | |
13 | + | |
14 | + def process(self): | |
15 | + res = {} | |
16 | + res["result"] = False | |
17 | + try: | |
18 | + user_guid = int(self.para.get("guid")) | |
19 | + userinfo = User.query.filter_by(id=user_guid).one_or_none() | |
20 | + if not userinfo: | |
21 | + res["msg"] = "用户不存在" | |
22 | + else: | |
23 | + db.session.delete(userinfo) | |
24 | + db.session.commit() | |
25 | + res["result"] = True | |
26 | + res["msg"] = "删除用户成功" | |
27 | + except Exception as e: | |
28 | + db.session.rollback() | |
29 | + raise e | |
30 | + return res | |
31 | + | |
32 | + api_doc = { | |
33 | + "tags": ["认证接口"], | |
34 | + "parameters": [ | |
35 | + {"name": "guid", | |
36 | + "in": "formData", | |
37 | + "type": "string", | |
38 | + "description": "用户id", | |
39 | + "required": "true"} | |
40 | + ], | |
41 | + "responses": { | |
42 | + 200: { | |
43 | + "schema": { | |
44 | + "properties": { | |
45 | + } | |
46 | + } | |
47 | + } | |
48 | + } | |
49 | + } | ... | ... |
app/modules/auth/user_query.py
0 → 100644
1 | +# coding=utf-8 | |
2 | +#author: qianyingz | |
3 | +#createtime: 2021/8/14 | |
4 | +#email: qianyingz@chinadci.com | |
5 | + | |
6 | +from authlib.oidc.core.claims import UserInfo | |
7 | +from .models import * | |
8 | +from app.util.component.ApiTemplate import ApiTemplate | |
9 | + | |
10 | + | |
11 | +class Api(ApiTemplate): | |
12 | + api_name = "获取用户列表" | |
13 | + | |
14 | + def para_check(self): | |
15 | + pass | |
16 | + | |
17 | + def process(self): | |
18 | + # 返回结果 | |
19 | + res = {} | |
20 | + res["result"] = False | |
21 | + try: | |
22 | + # 业务逻辑 | |
23 | + pass | |
24 | + page_index = int(self.para.get("page_index", "0")) | |
25 | + page_size = int(self.para.get("page_size", "1000")) | |
26 | + name = self.para.get("name") | |
27 | + id = self.para.get('guid') | |
28 | + | |
29 | + if id: | |
30 | + tmp_user = User.query.filter_by(id=id).first() | |
31 | + res["data"] = {"guid": tmp_user.id, "username": tmp_user.username, | |
32 | + "role": tmp_user.role, "company": tmp_user.company, | |
33 | + "position": tmp_user.position, "email": tmp_user.email, | |
34 | + "phone": tmp_user.phone} | |
35 | + else: | |
36 | + # 获取集合 | |
37 | + userLinq = User.query.order_by(User.id.desc()) | |
38 | + if name: | |
39 | + userLinq = userLinq.filter( | |
40 | + User.username.like("%" + name + "%")) | |
41 | + tmp_count = userLinq.count() | |
42 | + tmp_list = userLinq.limit(page_size).offset( | |
43 | + page_index * page_size).all() | |
44 | + res["data"] = { | |
45 | + "count": tmp_count, | |
46 | + "list": list(map(lambda t: | |
47 | + {"guid": t.id, "username": t.username, | |
48 | + "role": t.role}, | |
49 | + tmp_list))} | |
50 | + res["result"] = True | |
51 | + | |
52 | + except Exception as e: | |
53 | + raise e | |
54 | + return res | |
55 | + | |
56 | + api_doc = { | |
57 | + | |
58 | + "tags": ["认证接口"], | |
59 | + "parameters": [ | |
60 | + {"name": "page_index", | |
61 | + "in": "query", | |
62 | + "type": "int", | |
63 | + "description": "当前页", | |
64 | + "default": 0}, | |
65 | + {"name": "page_size", | |
66 | + "in": "query", | |
67 | + "type": "int", | |
68 | + "description": "条数", | |
69 | + "default": 1000}, | |
70 | + {"name": "name", | |
71 | + "in": "query", | |
72 | + "type": "string", | |
73 | + "description": "名称关键字"}, | |
74 | + {"name": "guid", | |
75 | + "in": "query", | |
76 | + "type": "string", | |
77 | + "description": "用户id,用于获取用户信息"} | |
78 | + ], | |
79 | + "responses": { | |
80 | + 200: { | |
81 | + "schema": { | |
82 | + "properties": { | |
83 | + } | |
84 | + } | |
85 | + } | |
86 | + } | |
87 | + } | ... | ... |
app/modules/auth/user_update.py
0 → 100644
1 | +from app.util.component.ApiTemplate import ApiTemplate | |
2 | +import time | |
3 | +from .models import * | |
4 | + | |
5 | + | |
6 | +class Api(ApiTemplate): | |
7 | + api_name = "更新用户信息" | |
8 | + | |
9 | + def para_check(self): | |
10 | + if not self.para.get("guid"): | |
11 | + raise Exception("guid is null") | |
12 | + return super().para_check() | |
13 | + | |
14 | + def process(self): | |
15 | + res = {} | |
16 | + res["result"] = False | |
17 | + try: | |
18 | + user_guid = int(self.para.get("guid")) | |
19 | + obj_value = {"company": "company", "email": "email", | |
20 | + "position": "position", "phone": "phone"} | |
21 | + | |
22 | + userinfo = User.query.filter_by(id=user_guid) | |
23 | + if not userinfo.one_or_none(): | |
24 | + res["msg"] = "数据不存在" | |
25 | + else: | |
26 | + # 更新密码要求同时输入pwd/newPwd/reNewPwd | |
27 | + if self.para.__contains__("pwd") or self.para.__contains__("newPwd") or self.para.__contains__("reNewPwd"): | |
28 | + password = self.para.get("pwd") | |
29 | + new_password = self.para.get("newPwd") | |
30 | + re_new_password = self.para.get("reNewPwd") | |
31 | + | |
32 | + # validate pwd | |
33 | + if not password: | |
34 | + res["result"] = False | |
35 | + res["msg"] = "无原密码" | |
36 | + return res | |
37 | + if new_password != re_new_password: | |
38 | + res["result"] = False | |
39 | + res["msg"] = "两次输入密码不一致" | |
40 | + return res | |
41 | + if userinfo.first().password != password: | |
42 | + res["result"] = False | |
43 | + res["msg"] = "原密码输入错误" | |
44 | + return res | |
45 | + | |
46 | + # 更新密码 | |
47 | + userinfo.update({"password": new_password}) | |
48 | + | |
49 | + #更新用户基本信息 | |
50 | + for key in obj_value: | |
51 | + if self.para.__contains__(obj_value[key]): | |
52 | + value = self.para.get(obj_value[key]) | |
53 | + value = "" if value == "None" or value == "none" else value | |
54 | + userinfo.update({key: value}) | |
55 | + | |
56 | + db.session.commit() | |
57 | + res["result"] = True | |
58 | + res["msg"] = "更新用户信息成功" | |
59 | + except Exception as e: | |
60 | + db.session.rollback() | |
61 | + raise e | |
62 | + return res | |
63 | + | |
64 | + api_doc = { | |
65 | + "tags": ["认证接口"], | |
66 | + "parameters": [ | |
67 | + {"name": "guid", | |
68 | + "in": "formData", | |
69 | + "type": "string", | |
70 | + "description": "用户id", | |
71 | + "required": "true"}, | |
72 | + {"name": "pwd", | |
73 | + "in": "formData", | |
74 | + "type": "string", | |
75 | + "description": "密码", | |
76 | + "required": ""}, | |
77 | + {"name": "newPwd", | |
78 | + "in": "formData", | |
79 | + "type": "string", | |
80 | + "description": "密码", | |
81 | + "required": ""}, | |
82 | + {"name": "reNewPwd", | |
83 | + "in": "formData", | |
84 | + "type": "string", | |
85 | + "description": "密码", | |
86 | + "required": ""}, | |
87 | + {"name": "company", | |
88 | + "in": "formData", | |
89 | + "type": "string", | |
90 | + "description": "单位", | |
91 | + "required": ""}, | |
92 | + {"name": "email", | |
93 | + "in": "formData", | |
94 | + "type": "string", | |
95 | + "description": "邮件", | |
96 | + "required": ""}, | |
97 | + {"name": "phone", | |
98 | + "in": "formData", | |
99 | + "type": "string", | |
100 | + "description": "电话", | |
101 | + "required": ""}, | |
102 | + {"name": "position", | |
103 | + "in": "formData", | |
104 | + "type": "string", | |
105 | + "description": "职位", | |
106 | + "required": ""}, | |
107 | + ], | |
108 | + "responses": { | |
109 | + 200: { | |
110 | + "schema": { | |
111 | + "properties": { | |
112 | + } | |
113 | + } | |
114 | + } | |
115 | + } | |
116 | + } | ... | ... |
1 | -html, | |
2 | -body { | |
3 | - font-family: Microsoft YaHei Regular, Microsoft YaHei Regular-Regular; | |
4 | -} | |
5 | - | |
6 | -html, | |
7 | -body, | |
8 | -p, | |
9 | -input { | |
10 | - margin: 0; | |
11 | - padding: 0; | |
12 | -} | |
13 | - | |
14 | -.login { | |
15 | - background: url(../images/login_background.png) no-repeat; | |
16 | - background-size: 100% 100%; | |
17 | - width: 100%; | |
18 | - height: 100%; | |
19 | - position: relative; | |
20 | -} | |
21 | - | |
22 | -.login-container { | |
23 | - position: absolute; | |
24 | - top: -50px; | |
25 | - bottom: 0; | |
26 | - left: 0; | |
27 | - right: 0; | |
28 | - margin: auto; | |
29 | - width: 900px; | |
30 | - height: 454px; | |
31 | - background: #ffffff; | |
32 | - border-radius: 4px; | |
33 | - box-shadow: 2px 0 21px 0 rgba(38, 106, 184, 0.53); | |
34 | -} | |
35 | - | |
36 | -.login-container-logo { | |
37 | - margin: 0; | |
38 | - background: url(../images/login_logo.png) no-repeat; | |
39 | - width: 401px; | |
40 | - height: 455px; | |
41 | - overflow: hidden; | |
42 | - float: left; | |
43 | -} | |
44 | - | |
45 | -.login-container-header { | |
46 | - font-size: 22px; | |
47 | - font-weight: 700; | |
48 | - text-align: left; | |
49 | - color: #545454; | |
50 | - letter-spacing: 1px; | |
51 | - text-align: center; | |
52 | - margin-bottom: 54px; | |
53 | -} | |
54 | - | |
55 | -.login-container-form { | |
56 | - margin-left: 401px; | |
57 | - height: 100%; | |
58 | - padding: 80px; | |
59 | -} | |
60 | - | |
61 | -.login-container-form .form-group { | |
62 | - width: 296px; | |
63 | - margin: 0 auto; | |
64 | - margin-top: 22px; | |
65 | -} | |
66 | - | |
67 | -.login-container-form .has-feedback.feedback-left .form-control-feedback { | |
68 | - left: 0; | |
69 | - right: auto; | |
70 | - width: 38px; | |
71 | - height: 45px; | |
72 | - line-height: 45px; | |
73 | - z-index: 4; | |
74 | - color: #dcdcdc; | |
75 | - font-size: 16px; | |
76 | -} | |
77 | - | |
78 | -.login-container-form .has-feedback.feedback-left .micons-pwd { | |
79 | - font-size: 18px; | |
80 | - line-height: 48px; | |
81 | -} | |
82 | - | |
83 | -.login-container-form .has-feedback.feedback-left .form-control { | |
84 | - padding-left: 38px; | |
85 | - padding-right: 12px; | |
86 | - border: 1px solid #ebebeb; | |
87 | - border-radius: 4px; | |
88 | - height: 45px; | |
89 | - color: #999; | |
90 | - font-size: 16px; | |
91 | - letter-spacing: 1px; | |
92 | -} | |
93 | - | |
94 | -.login-container-form .has-feedback.feedback-left .form-control:hover, | |
95 | -.login-container-form .has-feedback.feedback-left .form-control:hover, | |
96 | -.login-container-form .has-feedback.feedback-left .form-control:focus { | |
97 | - border: 1px solid #3081c3; | |
98 | - outline: unset; | |
99 | - box-shadow: unset; | |
100 | -} | |
101 | - | |
102 | -.login-container-form .overhidden { | |
103 | - padding-left: 24px; | |
104 | - font-size: 14px; | |
105 | - color: #999999; | |
106 | - vertical-align: bottom; | |
107 | - line-height: 18px; | |
108 | -} | |
109 | - | |
110 | -.login-container-form .overhidden:hover { | |
111 | - color: #3081c3; | |
112 | -} | |
113 | - | |
114 | -.login-container-form .ftdms-checkbox span::before { | |
115 | - height: 15px; | |
116 | - width: 15px; | |
117 | - border-width: 1px; | |
118 | - top: 2px; | |
119 | -} | |
120 | - | |
121 | -#btn-login { | |
122 | - background: #3081c3; | |
123 | - height: 45px; | |
124 | - font-size: 16px; | |
125 | - font-weight: 400; | |
126 | - color: #ffffff; | |
127 | - letter-spacing: 1px; | |
128 | -} | |
129 | - | |
130 | -#btn-login:hover { | |
131 | - background: #2ba3f6; | |
132 | -} | |
133 | - | |
134 | -.form-control:focus, | |
135 | -.form-control:hover { | |
136 | - box-shadow: unset; | |
137 | - border: 1px solid #3081c3 !important; | |
138 | -} | |
139 | - | |
140 | -.form-control { | |
141 | - width: 100%; | |
142 | -} | |
143 | - | |
144 | -.btn-info,.btn-info:active { | |
145 | - border: 1px solid; | |
146 | -} | |
147 | - | |
148 | -.btn { | |
149 | - padding: 8px 12px; | |
150 | - border-radius: 2px; | |
151 | - outline: none !important; | |
152 | - -webkit-transition: 0.15s linear; | |
153 | - transition: 0.15s linear; | |
154 | -} | |
155 | - | |
156 | -button { | |
157 | - display: block; | |
158 | - width: 100%; | |
159 | - margin-bottom: 0; | |
160 | - line-height: 1.42857143; | |
161 | - text-align: center; | |
162 | - white-space: nowrap; | |
163 | - touch-action: manipulation; | |
164 | - cursor: pointer; | |
165 | - user-select: none; | |
166 | - font-family: inherit; | |
167 | - overflow: visible; | |
168 | - margin: 0; | |
169 | - font: inherit; | |
170 | - outline: none !important; | |
171 | -} | |
172 | - | |
173 | -.ftdms-checkbox span::before, | |
174 | -.ftdms-radio span::before { | |
175 | - content: ''; | |
176 | - position: absolute; | |
177 | - display: inline-block; | |
178 | - height: 18px; | |
179 | - width: 18px; | |
180 | - left: 0.5px; | |
181 | - top: 0px; | |
182 | - border: 2px solid #ebebeb; | |
183 | - -webkit-transition: all 0.1s; | |
184 | - -o-transition: all 0.1s; | |
185 | - transition: all 0.1s; | |
186 | -} | |
187 | - | |
188 | -:after, | |
189 | -:before { | |
190 | - -webkit-box-sizing: border-box; | |
191 | - -moz-box-sizing: border-box; | |
192 | - box-sizing: border-box; | |
1 | +html, | |
2 | +body { | |
3 | + font-family: Microsoft YaHei Regular, Microsoft YaHei Regular-Regular; | |
4 | +} | |
5 | + | |
6 | +html, | |
7 | +body, | |
8 | +p, | |
9 | +input { | |
10 | + margin: 0; | |
11 | + padding: 0; | |
12 | +} | |
13 | + | |
14 | +.login { | |
15 | + background: url(../images/login_background.png) no-repeat; | |
16 | + background-size: 100% 100%; | |
17 | + width: 100%; | |
18 | + height: 100%; | |
19 | + position: relative; | |
20 | +} | |
21 | + | |
22 | +.login-container { | |
23 | + position: absolute; | |
24 | + top: -50px; | |
25 | + bottom: 0; | |
26 | + left: 0; | |
27 | + right: 0; | |
28 | + margin: auto; | |
29 | + width: 900px; | |
30 | + height: 454px; | |
31 | + background: #ffffff; | |
32 | + border-radius: 4px; | |
33 | + box-shadow: 2px 0 21px 0 rgba(38, 106, 184, 0.53); | |
34 | +} | |
35 | + | |
36 | +.login-container-logo { | |
37 | + margin: 0; | |
38 | + background: url(../images/login_logo.png) no-repeat; | |
39 | + width: 401px; | |
40 | + height: 455px; | |
41 | + overflow: hidden; | |
42 | + float: left; | |
43 | +} | |
44 | + | |
45 | +.login-container-header { | |
46 | + font-size: 22px; | |
47 | + font-weight: 700; | |
48 | + text-align: left; | |
49 | + color: #545454; | |
50 | + letter-spacing: 1px; | |
51 | + text-align: center; | |
52 | + margin-bottom: 54px; | |
53 | +} | |
54 | + | |
55 | +.login-container-header-small.login-container-header { | |
56 | + font-size: 22px; | |
57 | + font-weight: 700; | |
58 | + text-align: left; | |
59 | + color: #545454; | |
60 | + letter-spacing: 1px; | |
61 | + text-align: center; | |
62 | + margin-bottom: 22px; | |
63 | +} | |
64 | + | |
65 | +.login-container-form { | |
66 | + margin-left: 401px; | |
67 | + height: 100%; | |
68 | + padding: 80px; | |
69 | +} | |
70 | + | |
71 | +.login-container-form .form-tip { | |
72 | + margin-left: 21.5px; | |
73 | + color: red; | |
74 | + margin-bottom: 10px; | |
75 | + padding: 5px 6px; | |
76 | + width: 296px; | |
77 | + background: #ffebeb; | |
78 | + border: 1px solid #faccc6; | |
79 | + font-size: 11px; | |
80 | + border-radius: 4px; | |
81 | +} | |
82 | + | |
83 | +.login-container-form .form-tip { | |
84 | + height: 32px; | |
85 | +} | |
86 | + | |
87 | +.login-container-form .form-tip p { | |
88 | + margin: 0 0 0 5px; | |
89 | + line-height: 23px; | |
90 | +} | |
91 | + | |
92 | +.login-container-form .form-tip p, | |
93 | +.login-container-form .form-tip span { | |
94 | + display: block; | |
95 | + float: left; | |
96 | + height: 20px; | |
97 | +} | |
98 | + | |
99 | +.stop { | |
100 | + background: url(../images/stop.png) no-repeat; | |
101 | + width: 20px; | |
102 | + height: 20px; | |
103 | +} | |
104 | + | |
105 | +.login-container-form .form-group { | |
106 | + width: 296px; | |
107 | + margin: 0 auto; | |
108 | + margin-top: 22px; | |
109 | +} | |
110 | + | |
111 | +.login-container-form :first-child { | |
112 | + margin-top: 0px; | |
113 | +} | |
114 | + | |
115 | +.login-container-form .has-feedback.feedback-left .form-control-feedback { | |
116 | + left: 0; | |
117 | + right: auto; | |
118 | + width: 38px; | |
119 | + height: 45px; | |
120 | + line-height: 45px; | |
121 | + z-index: 4; | |
122 | + color: #dcdcdc; | |
123 | + font-size: 16px; | |
124 | +} | |
125 | + | |
126 | +.login-container-form .has-feedback.feedback-left .micons-pwd { | |
127 | + font-size: 18px; | |
128 | + line-height: 48px; | |
129 | +} | |
130 | + | |
131 | +.login-container-form .has-feedback.feedback-left .form-control { | |
132 | + padding-left: 38px; | |
133 | + padding-right: 12px; | |
134 | + border: 1px solid #ebebeb; | |
135 | + border-radius: 4px; | |
136 | + height: 45px; | |
137 | + color: #999; | |
138 | + font-size: 16px; | |
139 | + letter-spacing: 1px; | |
140 | +} | |
141 | + | |
142 | +.login-container-form .has-feedback.feedback-left .form-control:hover, | |
143 | +.login-container-form .has-feedback.feedback-left .form-control:hover, | |
144 | +.login-container-form .has-feedback.feedback-left .form-control:focus { | |
145 | + border: 1px solid #3081c3; | |
146 | + outline: unset; | |
147 | + box-shadow: unset; | |
148 | +} | |
149 | + | |
150 | +.login-container-form .overhidden { | |
151 | + padding-left: 24px; | |
152 | + font-size: 14px; | |
153 | + color: #999999; | |
154 | + vertical-align: bottom; | |
155 | + line-height: 18px; | |
156 | +} | |
157 | + | |
158 | +.login-container-form .overhidden:hover { | |
159 | + color: #3081c3; | |
160 | +} | |
161 | + | |
162 | +.login-container-form .ftdms-checkbox span::before { | |
163 | + height: 15px; | |
164 | + width: 15px; | |
165 | + border-width: 1px; | |
166 | + top: 2px; | |
167 | +} | |
168 | + | |
169 | +#btn-login { | |
170 | + background: #3081c3; | |
171 | + height: 45px; | |
172 | + font-size: 16px; | |
173 | + font-weight: 400; | |
174 | + color: #ffffff; | |
175 | + letter-spacing: 1px; | |
176 | +} | |
177 | + | |
178 | +#btn-login:hover { | |
179 | + background: #2ba3f6; | |
180 | +} | |
181 | + | |
182 | +.form-control:focus, | |
183 | +.form-control:hover { | |
184 | + box-shadow: unset; | |
185 | + border: 1px solid #3081c3 !important; | |
186 | +} | |
187 | + | |
188 | +.form-control { | |
189 | + width: 100%; | |
190 | +} | |
191 | + | |
192 | +.btn-info,.btn-info:active { | |
193 | + border: 1px solid; | |
194 | +} | |
195 | + | |
196 | +.btn { | |
197 | + padding: 8px 12px; | |
198 | + border-radius: 2px; | |
199 | + outline: none !important; | |
200 | + -webkit-transition: 0.15s linear; | |
201 | + transition: 0.15s linear; | |
202 | +} | |
203 | + | |
204 | +button { | |
205 | + display: block; | |
206 | + width: 100%; | |
207 | + margin-bottom: 0; | |
208 | + line-height: 1.42857143; | |
209 | + text-align: center; | |
210 | + white-space: nowrap; | |
211 | + touch-action: manipulation; | |
212 | + cursor: pointer; | |
213 | + user-select: none; | |
214 | + font-family: inherit; | |
215 | + overflow: visible; | |
216 | + margin: 0; | |
217 | + font: inherit; | |
218 | + outline: none !important; | |
219 | +} | |
220 | + | |
221 | +.ftdms-checkbox span::before, | |
222 | +.ftdms-radio span::before { | |
223 | + content: ''; | |
224 | + position: absolute; | |
225 | + display: inline-block; | |
226 | + height: 18px; | |
227 | + width: 18px; | |
228 | + left: 0.5px; | |
229 | + top: 0px; | |
230 | + border: 2px solid #ebebeb; | |
231 | + -webkit-transition: all 0.1s; | |
232 | + -o-transition: all 0.1s; | |
233 | + transition: all 0.1s; | |
234 | +} | |
235 | + | |
236 | +:after, | |
237 | +:before { | |
238 | + -webkit-box-sizing: border-box; | |
239 | + -moz-box-sizing: border-box; | |
240 | + box-sizing: border-box; | |
193 | 241 | } |
\ No newline at end of file | ... | ... |
app/static/content/images/stop.png
0 → 100644

356 Bytes
1 | -if (typeof(dmap) == "undefined") var dmap = {}; | |
2 | -dmap.login = { | |
3 | - init: function() { | |
4 | - $('#btn-login').bind('click', function(e) { | |
5 | - let username = $("#username").val(); | |
6 | - let password = $("#password").val(); | |
7 | - | |
8 | - if (username.length <= 0 || password.length <= 0) { | |
9 | - tips.notify("用户名或密码不能为空", "danger", 1e3); | |
10 | - return false; | |
11 | - } | |
12 | - | |
13 | - $.post("authorize", { username: username, password: password }) | |
14 | - }); | |
15 | - } | |
1 | +if (typeof(dmap) == "undefined") var dmap = {}; | |
2 | +dmap.login = { | |
3 | + init: function() { | |
4 | + $('#btn-login').bind('click', function(e) { | |
5 | + let username = $("#username").val(); | |
6 | + let password = $("#password").val(); | |
7 | + | |
8 | + if (username.length <= 0 || password.length <= 0) { | |
9 | + tips.notify("用户名或密码不能为空", "danger", 1e3); | |
10 | + return false; | |
11 | + } | |
12 | + | |
13 | + $.post("authorize", { username: username, password: password }, function(data) { | |
14 | + if (!data.result) { | |
15 | + tips.notify("账号或密码错误", "danger", 1e3); | |
16 | + } | |
17 | + }) | |
18 | + }); | |
19 | + } | |
16 | 20 | }; |
\ No newline at end of file | ... | ... |
1 | -<html> | |
2 | - <head> | |
3 | - <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | |
4 | - <title>DMap Server</title> | |
5 | - <link | |
6 | - rel="stylesheet" | |
7 | - type="text/css" | |
8 | - href="{{ url_for('static', filename = 'content/css/login.css') }}" | |
9 | - /> | |
10 | - <link | |
11 | - rel="stylesheet" | |
12 | - type="text/css" | |
13 | - href="{{ url_for('static', filename = 'content/css/font.css') }}" | |
14 | - /> | |
15 | - <link | |
16 | - rel="stylesheet" | |
17 | - type="text/css" | |
18 | - href="{{ url_for('static', filename = 'content/css/bootstrap.min.css') }}" | |
19 | - /> | |
20 | - <script src="{{ url_for('static',filename='content/js/jquery.min.js') }}"></script> | |
21 | - <script src="{{ url_for('static',filename='content/js/bootstrap-notify.min.js') }}"></script> | |
22 | - <script src="{{ url_for('static',filename='content/js/tips.js') }}"></script> | |
23 | - <script src="{{ url_for('static',filename='content/js/login.js') }}"></script> | |
24 | - </head> | |
25 | -</html> | |
26 | - | |
27 | -<div class="login"> | |
28 | - <div class="login-container"> | |
29 | - <p class="login-container-logo"></p> | |
30 | - <div class="login-container-form"> | |
31 | - <p class="login-container-header">广州城市信息研究所有限公司</p> | |
32 | - <form action="" method="post"> | |
33 | - <div class="form-group has-feedback feedback-left"> | |
34 | - <input | |
35 | - type="text" | |
36 | - placeholder="用户名" | |
37 | - maxlength="20" | |
38 | - autocomplete="off" | |
39 | - class="form-control border-info" | |
40 | - name="username" | |
41 | - id="username" | |
42 | - /> | |
43 | - <span class="micons-user form-control-feedback"></span> | |
44 | - </div> | |
45 | - | |
46 | - <div class="form-group has-feedback feedback-left"> | |
47 | - <input | |
48 | - type="password" | |
49 | - placeholder="密码" | |
50 | - maxlength="20" | |
51 | - autocomplete="off" | |
52 | - class="form-control border-info" | |
53 | - id="password" | |
54 | - name="password" | |
55 | - /> | |
56 | - <span class="micons-pwd form-control-feedback"></span> | |
57 | - </div> | |
58 | - | |
59 | - <div class="form-group"> | |
60 | - <button class="btn btn-block btn-info" type="submit" id="btn-login"> | |
61 | - 立即登录 | |
62 | - </button> | |
63 | - </div> | |
64 | - </form> | |
65 | - </div> | |
66 | - <div class="clear"></div> | |
67 | - </div> | |
68 | -</div> | |
69 | -<script> | |
70 | - $(function () {}) | |
71 | -</script> | |
1 | +<html> | |
2 | + <head> | |
3 | + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | |
4 | + <title>DMap Server</title> | |
5 | + <link | |
6 | + rel="stylesheet" | |
7 | + type="text/css" | |
8 | + href="{{ url_for('static', filename = 'content/css/login.css') }}" | |
9 | + /> | |
10 | + <link | |
11 | + rel="stylesheet" | |
12 | + type="text/css" | |
13 | + href="{{ url_for('static', filename = 'content/css/font.css') }}" | |
14 | + /> | |
15 | + <link | |
16 | + rel="stylesheet" | |
17 | + type="text/css" | |
18 | + href="{{ url_for('static', filename = 'content/css/bootstrap.min.css') }}" | |
19 | + /> | |
20 | + <script src="{{ url_for('static',filename='content/js/jquery.min.js') }}"></script> | |
21 | + <script src="{{ url_for('static',filename='content/js/bootstrap-notify.min.js') }}"></script> | |
22 | + <script src="{{ url_for('static',filename='content/js/tips.js') }}"></script> | |
23 | + <script src="{{ url_for('static',filename='content/js/login.js') }}"></script> | |
24 | + </head> | |
25 | +</html> | |
26 | + | |
27 | +<div class="login"> | |
28 | + <div class="login-container"> | |
29 | + <p class="login-container-logo"></p> | |
30 | + <div class="login-container-form"> | |
31 | + | |
32 | + {%if error%} | |
33 | + <p class="login-container-header-small login-container-header">广州城市信息研究所有限公司</p> | |
34 | + <div class="form-tip"> | |
35 | + <span class="stop"></span> | |
36 | + <p>{{error}}</p> | |
37 | + </div> | |
38 | + {% else %} | |
39 | + <p class="login-container-header">广州城市信息研究所有限公司</p> | |
40 | + {% endif %} | |
41 | + | |
42 | + <form action="" method="post"> | |
43 | + <div class="form-group has-feedback feedback-left"> | |
44 | + <input | |
45 | + type="text" | |
46 | + placeholder="用户名" | |
47 | + maxlength="20" | |
48 | + autocomplete="off" | |
49 | + class="form-control border-info" | |
50 | + name="username" | |
51 | + id="username" | |
52 | + /> | |
53 | + <span class="micons-user form-control-feedback"></span> | |
54 | + </div> | |
55 | + | |
56 | + <div class="form-group has-feedback feedback-left"> | |
57 | + <input | |
58 | + type="password" | |
59 | + placeholder="密码" | |
60 | + maxlength="20" | |
61 | + autocomplete="off" | |
62 | + class="form-control border-info" | |
63 | + id="password" | |
64 | + name="password" | |
65 | + /> | |
66 | + <span class="micons-pwd form-control-feedback"></span> | |
67 | + </div> | |
68 | + | |
69 | + <div class="form-group"> | |
70 | + <button class="btn btn-block btn-info" type="submit" id="btn-login"> | |
71 | + 立即登录 | |
72 | + </button> | |
73 | + </div> | |
74 | + </form> | |
75 | + </div> | |
76 | + <div class="clear"></div> | |
77 | + </div> | |
78 | +</div> | |
79 | +<script> | |
80 | + $(function () {}) | |
81 | +</script> | ... | ... |
1 | -# coding=utf-8 | |
2 | -from flask import Flask | |
3 | -from app import create_app | |
4 | -app:Flask = create_app() | |
5 | -if __name__ == '__main__': | |
6 | - app.run(host="0.0.0.0", port="8840", threaded=True, debug=True) | |
7 | - # app.run(host="0.0.0.0", port="8840", threaded=True) | |
\ No newline at end of file | ||
1 | +# coding=utf-8 | |
2 | +from flask import Flask | |
3 | +from app import create_app | |
4 | +import os | |
5 | +os.environ['AUTHLIB_INSECURE_TRANSPORT'] = '1' | |
6 | +app: Flask = create_app() | |
7 | +if __name__ == '__main__': | |
8 | + app.run(host="0.0.0.0", port="8840", threaded=True, debug=True) | |
9 | + # app.run(host="0.0.0.0", port="8840", threaded=True) | ... | ... |
请
注册
或
登录
后发表评论