提交 6f1208765d6b1cf3c3abbb8e4a473f5251810ce9

作者 qianyingz
2 个父辈 111aa1ab 83e89ac0

用户管理加密、鉴权支持自定义重定向地址

1 import decimal 1 import decimal
  2 +from re import template
2 3
3 from flask import Flask as _Flask 4 from flask import Flask as _Flask
4 from flask.json import JSONEncoder as _JSONEncoder 5 from flask.json import JSONEncoder as _JSONEncoder
@@ -58,18 +59,47 @@ def create_app(): @@ -58,18 +59,47 @@ def create_app():
58 app.config['OAUTH2_JWT_KEY'] = 'secret-key' 59 app.config['OAUTH2_JWT_KEY'] = 'secret-key'
59 app.config['OAUTH2_JWT_ALG'] = 'HS256' 60 app.config['OAUTH2_JWT_ALG'] = 'HS256'
60 # app.config['SQLALCHEMY_ECHO'] = True 61 # app.config['SQLALCHEMY_ECHO'] = True
61 - 62 +
62 # allows cookies and credentials to be submitted across domains 63 # allows cookies and credentials to be submitted across domains
63 app.config['CORS_SUPPORTS_CREDENTIALS'] = true 64 app.config['CORS_SUPPORTS_CREDENTIALS'] = true
64 - app.config['CORS_ORIGINS ']="*" 65 + app.config['CORS_ORIGINS '] = "*"
65 66
66 # 跨域设置 67 # 跨域设置
67 CORS(app) 68 CORS(app)
68 69
69 # swagger设置 70 # swagger设置
70 swagger_config = Swagger.DEFAULT_CONFIG 71 swagger_config = Swagger.DEFAULT_CONFIG
71 - swagger_config.update({"title": "DMapManager"})  
72 - Swagger(app, config=swagger_config) 72 +
  73 + SWAGGER_TEMPLATE = {
  74 + # "openapi": "3.0.0",
  75 + # "components": {
  76 + # "securitySchemes": {
  77 + # "bearerAuth": {
  78 + # "type": "http",
  79 + # "scheme": "bearer",
  80 + # "bearerFormat": "JWT"
  81 + # },
  82 + # }
  83 + # },
  84 + "securityDefinitions": {
  85 + "APIKeyHeader": {
  86 + "type": "apiKey",
  87 + "in": "header",
  88 + "name": "Authorization"
  89 + }
  90 + },
  91 +
  92 + "security": [{
  93 + "APIKeyHeader": []
  94 + }
  95 + ]
  96 + }
  97 +
  98 + swagger_config = Swagger.DEFAULT_CONFIG
  99 + swagger_config.update(configure.swagger_configure)
  100 +
  101 + Swagger(app, config=swagger_config,
  102 + template=SWAGGER_TEMPLATE)
73 103
74 # 创建数据库 104 # 创建数据库
75 db.init_app(app) 105 db.init_app(app)
@@ -78,9 +108,12 @@ def create_app(): @@ -78,9 +108,12 @@ def create_app():
78 # 日志 108 # 日志
79 109
80 logging.basicConfig(level=configure.log_level) 110 logging.basicConfig(level=configure.log_level)
81 - log_file = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "logs", "log.txt")  
82 - handler = logging.FileHandler(log_file, encoding='UTF-8') # 设置日志字符集和存储路径名字  
83 - logging_format = logging.Formatter('[%(levelname)s] %(asctime)s %(message)s') 111 + log_file = os.path.join(os.path.dirname(os.path.dirname(
  112 + os.path.realpath(__file__))), "logs", "log.txt")
  113 + handler = logging.FileHandler(
  114 + log_file, encoding='UTF-8') # 设置日志字符集和存储路径名字
  115 + logging_format = logging.Formatter(
  116 + '[%(levelname)s] %(asctime)s %(message)s')
84 handler.setFormatter(logging_format) 117 handler.setFormatter(logging_format)
85 118
86 app.logger.addHandler(handler) 119 app.logger.addHandler(handler)
@@ -99,6 +132,7 @@ def create_app(): @@ -99,6 +132,7 @@ def create_app():
99 # start_schedule() 132 # start_schedule()
100 return app 133 return app
101 134
  135 +
102 def create_schedule(): 136 def create_schedule():
103 monitor = Flask(__name__) 137 monitor = Flask(__name__)
104 monitor.config['SQLALCHEMY_DATABASE_URI'] = configure.SQLALCHEMY_DATABASE_URI 138 monitor.config['SQLALCHEMY_DATABASE_URI'] = configure.SQLALCHEMY_DATABASE_URI
@@ -109,12 +143,12 @@ def create_schedule(): @@ -109,12 +143,12 @@ def create_schedule():
109 143
110 # allows cookies and credentials to be submitted across domains 144 # allows cookies and credentials to be submitted across domains
111 monitor.config['CORS_SUPPORTS_CREDENTIALS'] = true 145 monitor.config['CORS_SUPPORTS_CREDENTIALS'] = true
112 - monitor.config['CORS_ORIGINS ']="*"  
113 - 146 + monitor.config['CORS_ORIGINS '] = "*"
  147 +
114 # swagger设置 148 # swagger设置
115 swagger_config = Swagger.DEFAULT_CONFIG 149 swagger_config = Swagger.DEFAULT_CONFIG
116 Swagger(monitor, config=swagger_config) 150 Swagger(monitor, config=swagger_config)
117 - 151 +
118 # 创建数据库 152 # 创建数据库
119 db.init_app(monitor) 153 db.init_app(monitor)
120 db.create_all(app=monitor) 154 db.create_all(app=monitor)
@@ -124,9 +158,12 @@ def create_schedule(): @@ -124,9 +158,12 @@ def create_schedule():
124 158
125 # 日志 159 # 日志
126 logging.basicConfig(level=configure.log_level) 160 logging.basicConfig(level=configure.log_level)
127 - log_file = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "logs", "monitor_log.txt")  
128 - handler = logging.FileHandler(log_file, encoding='UTF-8') # 设置日志字符集和存储路径名字  
129 - logging_format = logging.Formatter('[%(levelname)s] %(asctime)s %(message)s') 161 + log_file = os.path.join(os.path.dirname(os.path.dirname(
  162 + os.path.realpath(__file__))), "logs", "monitor_log.txt")
  163 + handler = logging.FileHandler(
  164 + log_file, encoding='UTF-8') # 设置日志字符集和存储路径名字
  165 + logging_format = logging.Formatter(
  166 + '[%(levelname)s] %(asctime)s %(message)s')
130 handler.setFormatter(logging_format) 167 handler.setFormatter(logging_format)
131 monitor.logger.addHandler(handler) 168 monitor.logger.addHandler(handler)
132 169
@@ -4,20 +4,62 @@ import os @@ -4,20 +4,62 @@ import os
4 from flask_sqlalchemy import SQLAlchemy 4 from flask_sqlalchemy import SQLAlchemy
5 import glob 5 import glob
6 import traceback 6 import traceback
7 -from pyDes import des,PAD_PKCS5,ECB  
8 - 7 +from pyDes import des, PAD_PKCS5, ECB
  8 +import json
9 import base64 9 import base64
  10 +from gmssl import sm3, func
  11 +from Crypto.Cipher import AES
  12 +from Crypto.Util.Padding import unpad, pad
  13 +from cryptography.hazmat.primitives import padding
  14 +from cryptography.hazmat.primitives.ciphers import algorithms
  15 +from binascii import b2a_hex, a2b_hex
  16 +
  17 +
  18 +class AESHelper():
  19 + key = 'w03MyIgc3zMHM5Qe'.encode('utf-8')
  20 + iv = '8765432187654321'.encode('utf-8')
  21 +
  22 + @classmethod
  23 + def encode(self, instr):
  24 + plaintxt = self._pad(instr)
  25 + aes = AES.new(self.key, AES.MODE_CBC, self.iv)
  26 + ciphertext = aes.encrypt(plaintxt)
  27 + return b2a_hex(ciphertext).decode('utf-8')
  28 +
  29 + @classmethod
  30 + def decode(self, instr):
  31 + encryptedData = instr
  32 + aes = AES.new(self.key, AES.MODE_CBC, self.iv)
  33 + plaintxt = aes.decrypt(a2b_hex(encryptedData))
  34 + return bytes.decode(unpad(plaintxt, AES.block_size))
  35 +
  36 + def _pad(data):
  37 + if not isinstance(data, bytes):
  38 + data = data.encode()
  39 + padder = padding.PKCS7(algorithms.AES.block_size).padder()
  40 + padded_data = padder.update(data)+padder.finalize()
  41 + return padded_data
  42 +
  43 +
  44 +class SM3():
  45 + @classmethod
  46 + def encode(self, data=""):
  47 + by_str = bytes(data, 'utf-8')
  48 + result = sm3.sm3_hash(func.bytes_to_list(by_str))
  49 + return result
  50 +
  51 +
10 class DES(): 52 class DES():
11 ''' 53 '''
12 DES密码加解密 54 DES密码加解密
13 ''' 55 '''
14 - Des: des = des("Chinadci", ECB, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5) 56 + Des: des = des("Chinadci", ECB, "\0\0\0\0\0\0\0\0",
  57 + pad=None, padmode=PAD_PKCS5)
15 58
16 @classmethod 59 @classmethod
17 def encode(cls, data): 60 def encode(cls, data):
18 return str(base64.b64encode(cls.Des.encrypt(data)), encoding="utf8") 61 return str(base64.b64encode(cls.Des.encrypt(data)), encoding="utf8")
19 62
20 -  
21 @classmethod 63 @classmethod
22 def decode(cls, data): 64 def decode(cls, data):
23 if data: 65 if data:
@@ -26,6 +68,7 @@ class DES(): @@ -26,6 +68,7 @@ class DES():
26 else: 68 else:
27 return data 69 return data
28 70
  71 +
29 db = SQLAlchemy() 72 db = SQLAlchemy()
30 73
31 # 动态加载Model 74 # 动态加载Model
@@ -33,13 +76,14 @@ current_dir = os.path.abspath(os.path.dirname(__file__)) @@ -33,13 +76,14 @@ current_dir = os.path.abspath(os.path.dirname(__file__))
33 pkgs = list(glob.glob('%s/modules/*/models' % (current_dir))) 76 pkgs = list(glob.glob('%s/modules/*/models' % (current_dir)))
34 pkgs.extend(list(glob.glob('%s/modules/*/*/models' % (current_dir)))) 77 pkgs.extend(list(glob.glob('%s/modules/*/*/models' % (current_dir))))
35 78
36 -for pkg in pkgs : 79 +for pkg in pkgs:
37 pkg = os.path.normpath(pkg) 80 pkg = os.path.normpath(pkg)
38 node_list = pkg.split(os.path.sep) 81 node_list = pkg.split(os.path.sep)
39 - pkg_name = "app.{}".format(".".join(node_list[node_list.index("modules"):])) 82 + pkg_name = "app.{}".format(
  83 + ".".join(node_list[node_list.index("modules"):]))
40 try: 84 try:
41 if pkg_name.__contains__("models"): 85 if pkg_name.__contains__("models"):
42 __import__(pkg_name) 86 __import__(pkg_name)
43 except Exception as e: 87 except Exception as e:
44 print(traceback.format_exc()) 88 print(traceback.format_exc())
45 - pass  
  89 + pass
1 from enum import auto 1 from enum import auto
2 from logging import error 2 from logging import error
  3 +from unittest import result
3 from flasgger import swag_from 4 from flasgger import swag_from
4 from app.util import BlueprintApi 5 from app.util import BlueprintApi
5 from app.util import BlueprintApi 6 from app.util import BlueprintApi
6 from flask import Blueprint, render_template, redirect, request, session, jsonify 7 from flask import Blueprint, render_template, redirect, request, session, jsonify
7 -from sqlalchemy import and_  
8 from .models import * 8 from .models import *
9 -from .oauth2 import authorization, generate_user_info,require_oauth 9 +from .oauth2 import authorization, generate_user_info, require_oauth
10 from authlib.oauth2 import OAuth2Error 10 from authlib.oauth2 import OAuth2Error
11 from authlib.integrations.flask_oauth2 import current_token 11 from authlib.integrations.flask_oauth2 import current_token
12 from . import user_create, client_create, client_query, user_query, user_update, user_delete 12 from . import user_create, client_create, client_query, user_query, user_update, user_delete
13 import configure 13 import configure
14 from app.decorators.auth_decorator import auth_decorator 14 from app.decorators.auth_decorator import auth_decorator
  15 +import time
  16 +from app.models import SM3, AESHelper
15 17
16 18
17 def current_user(): 19 def current_user():
@@ -45,17 +47,22 @@ class DataManager(BlueprintApi): @@ -45,17 +47,22 @@ class DataManager(BlueprintApi):
45 except OAuth2Error as error: 47 except OAuth2Error as error:
46 return jsonify(dict(error.get_body())) 48 return jsonify(dict(error.get_body()))
47 if not user: 49 if not user:
48 - return render_template("auth/authorize.html", user=user, grant=grant)  
49 - # return render_template("auth/login1.html", user=user, grant=grant) 50 + # 生成验证码
  51 +
  52 + return render_template("auth/authorize.html",
  53 + user=user,
  54 + grant=grant)
50 error = "" 55 error = ""
51 if not user: 56 if not user:
  57 + # 验证码校验
  58 +
52 if not "username" in request.form or not request.form.get("username"): 59 if not "username" in request.form or not request.form.get("username"):
53 error = "用户名不可为空" 60 error = "用户名不可为空"
54 elif not "password" in request.form or not request.form.get("password"): 61 elif not "password" in request.form or not request.form.get("password"):
55 error = "密码不可为空" 62 error = "密码不可为空"
56 else: 63 else:
57 username = request.form.get("username") 64 username = request.form.get("username")
58 - password = request.form.get("password") 65 + password = SM3.encode(request.form.get("password"))
59 user = User.query.filter_by( 66 user = User.query.filter_by(
60 username=username, password=password).first() 67 username=username, password=password).first()
61 if not user: 68 if not user:
@@ -64,15 +71,14 @@ class DataManager(BlueprintApi): @@ -64,15 +71,14 @@ class DataManager(BlueprintApi):
64 if user: 71 if user:
65 session["id"] = user.id 72 session["id"] = user.id
66 grant_user = user 73 grant_user = user
67 - return authorization.create_authorization_response(grant_user=grant_user) 74 + return authorization.create_authorization_response(request=request, grant_user=grant_user)
68 75
69 try: 76 try:
70 grant = authorization.validate_consent_request(end_user=user) 77 grant = authorization.validate_consent_request(end_user=user)
71 except OAuth2Error as error: 78 except OAuth2Error as error:
72 return jsonify(dict(error.get_body())) 79 return jsonify(dict(error.get_body()))
73 - return render_template("auth/authorize.html", user=user, grant=grant, error=error)  
74 -  
75 - 80 + # return render_template("auth/authorize.html", user=user, grant=grant, error=error)
  81 + return authorization.create_authorization_response(grant_user=None)
76 82
77 @staticmethod 83 @staticmethod
78 @bp.route("/token", methods=["POST"]) 84 @bp.route("/token", methods=["POST"])
@@ -106,8 +112,7 @@ class DataManager(BlueprintApi): @@ -106,8 +112,7 @@ class DataManager(BlueprintApi):
106 except OAuth2Error as error: 112 except OAuth2Error as error:
107 return jsonify(dict(error.get_body())) 113 return jsonify(dict(error.get_body()))
108 return redirect(url) 114 return redirect(url)
109 -  
110 - 115 +
111 """接口""" 116 """接口"""
112 @staticmethod 117 @staticmethod
113 @bp.route("/users", methods=["GET"]) 118 @bp.route("/users", methods=["GET"])
@@ -166,3 +171,29 @@ class DataManager(BlueprintApi): @@ -166,3 +171,29 @@ class DataManager(BlueprintApi):
166 获取client列表 171 获取client列表
167 """ 172 """
168 return client_query.Api().result 173 return client_query.Api().result
  174 +
  175 + @staticmethod
  176 + @bp.route("/init", methods=["GET"])
  177 + def init():
  178 + username = 'admin'
  179 + password = 'admin'
  180 + if not User.query.filter_by(username=username).one_or_none():
  181 + user = User(username=username, password=password, role='admin',
  182 + phone='', company='', position='', email='',
  183 + create_time=time.strftime(
  184 + "%Y-%m-%d %H:%M:%S", time.localtime()),
  185 + update_time=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
  186 + db.sesion.add(user)
  187 + db.session.commit()
  188 + return "创建默认用户成功"
  189 + else:
  190 + return "默认用户已存在"
  191 +
  192 + @staticmethod
  193 + @bp.route("/test", methods=["GET"])
  194 + def test():
  195 + result = 'c78ca1de8139e62c99d4c4d2050ddd16'
  196 + result = AESHelper.encode('dataman2')
  197 + # result=DES.decode('U2FsdGVkX199Ncuh7+0/HVmonwM9Uz7SYnmF73wtW7c=')
  198 + result2 = AESHelper.decode(result)
  199 + return result2
@@ -40,6 +40,13 @@ class OAuth2Client(db.Model, OAuth2ClientMixin): @@ -40,6 +40,13 @@ class OAuth2Client(db.Model, OAuth2ClientMixin):
40 Integer, ForeignKey('dmap_user.id', ondelete='CASCADE')) 40 Integer, ForeignKey('dmap_user.id', ondelete='CASCADE'))
41 user = relationship('User') 41 user = relationship('User')
42 42
  43 + def get_default_redirect_uri(self):
  44 + if self.redirect_uris:
  45 + return self.redirect_uris[0]
  46 +
  47 + def check_redirect_uri(self, redirect_uri):
  48 + return redirect_uri in self.redirect_uris
  49 +
43 50
44 class OAuth2AuthorizationCode(db.Model, OAuth2AuthorizationCodeMixin): 51 class OAuth2AuthorizationCode(db.Model, OAuth2AuthorizationCodeMixin):
45 __tablename__ = 'dmap_oauth2_code' 52 __tablename__ = 'dmap_oauth2_code'
@@ -57,4 +64,4 @@ class OAuth2Token(db.Model, OAuth2TokenMixin): @@ -57,4 +64,4 @@ class OAuth2Token(db.Model, OAuth2TokenMixin):
57 user_id = Column( 64 user_id = Column(
58 Integer, ForeignKey('dmap_user.id', ondelete='CASCADE')) 65 Integer, ForeignKey('dmap_user.id', ondelete='CASCADE'))
59 # name = Column(Text) 66 # name = Column(Text)
60 - user = relationship('User')  
  67 + user = relationship('User')
  1 +from authlib.oauth2.rfc6749 import grants
1 from os import access, remove 2 from os import access, remove
2 from time import time 3 from time import time
3 from authlib.integrations.flask_oauth2 import ( 4 from authlib.integrations.flask_oauth2 import (
@@ -29,10 +30,11 @@ DUMMY_JWT_CONFIG = { @@ -29,10 +30,11 @@ DUMMY_JWT_CONFIG = {
29 'exp': 7200, 30 'exp': 7200,
30 } 31 }
31 32
  33 +
32 class myCodeIDToken(CodeIDToken): 34 class myCodeIDToken(CodeIDToken):
33 def validate(self, now, leeway): 35 def validate(self, now, leeway):
34 return super().validate(now=now, leeway=leeway) 36 return super().validate(now=now, leeway=leeway)
35 - 37 +
36 def validate_exp(self, now, leeway): 38 def validate_exp(self, now, leeway):
37 return super().validate_exp(now, leeway) 39 return super().validate_exp(now, leeway)
38 40
@@ -68,7 +70,34 @@ def create_authorization_code(client, grant_user, request): @@ -68,7 +70,34 @@ def create_authorization_code(client, grant_user, request):
68 return code 70 return code
69 71
70 72
71 -class AuthorizationCodeGrant(_AuthorizationCodeGrant): 73 +class AuthorizationCodeGrant(grants.AuthorizationCodeGrant):
  74 +
  75 + def save_authorization_code(self, code, request):
  76 + client = request.client
  77 + auth_code = OAuth2AuthorizationCode(
  78 + code=code,
  79 + client_id=client.client_id,
  80 + redirect_uri=request.redirect_uri,
  81 + scope=request.scope,
  82 + user_id=request.user.id,
  83 + )
  84 + db.session.add(auth_code)
  85 + db.session.commit()
  86 + return auth_code
  87 +
  88 + def query_authorization_code(self, code, client):
  89 + item = OAuth2AuthorizationCode.query.filter_by(
  90 + code=code, client_id=client.client_id).first()
  91 + if item and not item.is_expired():
  92 + return item
  93 +
  94 + def delete_authorization_code(self, authorization_code):
  95 + db.session.delete(authorization_code)
  96 + db.session.commit()
  97 +
  98 + def authenticate_user(self, authorization_code):
  99 + return User.query.get(authorization_code.user_id)
  100 +
72 def create_authorization_code(self, client, grant_user, request): 101 def create_authorization_code(self, client, grant_user, request):
73 return create_authorization_code(client, grant_user, request) 102 return create_authorization_code(client, grant_user, request)
74 103
@@ -122,6 +151,17 @@ class HybridGrant(_OpenIDHybridGrant): @@ -122,6 +151,17 @@ class HybridGrant(_OpenIDHybridGrant):
122 return generate_user_info(user, scope) 151 return generate_user_info(user, scope)
123 152
124 153
  154 +class PasswordGrant(grants.ResourceOwnerPasswordCredentialsGrant):
  155 + def authenticate_user(self, username, password):
  156 + user = User.query.filter_by(username=username).first()
  157 + if user.check_password(password):
  158 + return user
  159 +
  160 + TOKEN_ENDPOINT_AUTH_METHODS = [
  161 + 'client_secret_basic', 'client_secret_post'
  162 + ]
  163 +
  164 +
125 authorization = AuthorizationServer() 165 authorization = AuthorizationServer()
126 require_oauth = ResourceProtector() 166 require_oauth = ResourceProtector()
127 167
@@ -142,6 +182,7 @@ def config_oauth(app): @@ -142,6 +182,7 @@ def config_oauth(app):
142 ]) 182 ])
143 authorization.register_grant(ImplicitGrant) 183 authorization.register_grant(ImplicitGrant)
144 authorization.register_grant(HybridGrant) 184 authorization.register_grant(HybridGrant)
  185 + authorization.register_grant(PasswordGrant)
145 186
146 # protect resource 187 # protect resource
147 bearer_cls = create_bearer_token_validator(db.session, OAuth2Token) 188 bearer_cls = create_bearer_token_validator(db.session, OAuth2Token)
@@ -6,6 +6,8 @@ @@ -6,6 +6,8 @@
6 from .models import * 6 from .models import *
7 from app.util.component.ApiTemplate import ApiTemplate 7 from app.util.component.ApiTemplate import ApiTemplate
8 import time 8 import time
  9 +from app.models import SM3
  10 +from app.models import AESHelper
9 11
10 12
11 class Api(ApiTemplate): 13 class Api(ApiTemplate):
@@ -26,13 +28,13 @@ class Api(ApiTemplate): @@ -26,13 +28,13 @@ class Api(ApiTemplate):
26 res["result"] = False 28 res["result"] = False
27 try: 29 try:
28 # 业务逻辑 30 # 业务逻辑
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) 31 + username = AESHelper.decode( self.para.get("username", ''))
  32 + password = SM3.encode(AESHelper.decode(self.para.get("pwd", '')))
  33 + role = AESHelper.decode(self.para.get("role", ''))
  34 + company = AESHelper.decode(self.para.get("company", ''))
  35 + position = AESHelper.decode(self.para.get("position", ''))
  36 + email = AESHelper.decode(self.para.get("email", ''))
  37 + phone = AESHelper.decode(self.para.get("phone", ''))
36 # 是否重名 38 # 是否重名
37 if(User.query.filter_by(username=username).one_or_none()): 39 if(User.query.filter_by(username=username).one_or_none()):
38 res["msg"] = "username 已存在" 40 res["msg"] = "username 已存在"
1 from app.util.component.ApiTemplate import ApiTemplate 1 from app.util.component.ApiTemplate import ApiTemplate
2 -import time 2 +from app.models import SM3
3 from .models import * 3 from .models import *
  4 +from app.models import AESHelper
4 5
5 6
6 class Api(ApiTemplate): 7 class Api(ApiTemplate):
@@ -25,10 +26,13 @@ class Api(ApiTemplate): @@ -25,10 +26,13 @@ class Api(ApiTemplate):
25 else: 26 else:
26 # 更新密码要求同时输入pwd/newPwd/reNewPwd 27 # 更新密码要求同时输入pwd/newPwd/reNewPwd
27 if self.para.__contains__("pwd") or self.para.__contains__("newPwd") or self.para.__contains__("reNewPwd"): 28 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 - 29 + password = SM3.encode(
  30 + AESHelper.decode(self.para.get("pwd")))
  31 + new_password = SM3.encode(
  32 + AESHelper.decode(self.para.get("newPwd")))
  33 + re_new_password = SM3.encode(
  34 + AESHelper.decode(self.para.get("reNewPwd")))
  35 +
32 # validate pwd 36 # validate pwd
33 if not password: 37 if not password:
34 res["result"] = False 38 res["result"] = False
@@ -42,17 +46,17 @@ class Api(ApiTemplate): @@ -42,17 +46,17 @@ class Api(ApiTemplate):
42 res["result"] = False 46 res["result"] = False
43 res["msg"] = "原密码输入错误" 47 res["msg"] = "原密码输入错误"
44 return res 48 return res
45 - 49 +
46 # 更新密码 50 # 更新密码
47 userinfo.update({"password": new_password}) 51 userinfo.update({"password": new_password})
48 -  
49 - #更新用户基本信息 52 +
  53 + # 更新用户基本信息
50 for key in obj_value: 54 for key in obj_value:
51 if self.para.__contains__(obj_value[key]): 55 if self.para.__contains__(obj_value[key]):
52 - value = self.para.get(obj_value[key]) 56 + value = self.para.get(AESHelper.decode(obj_value[key]))
53 value = "" if value == "None" or value == "none" else value 57 value = "" if value == "None" or value == "none" else value
54 userinfo.update({key: value}) 58 userinfo.update({key: value})
55 - 59 +
56 db.session.commit() 60 db.session.commit()
57 res["result"] = True 61 res["result"] = True
58 res["msg"] = "更新用户信息成功" 62 res["msg"] = "更新用户信息成功"
  1 +'''
  2 +生成验证码图片
  3 +'''
  4 +
  5 +from PIL import Image, ImageDraw, ImageFont, ImageFilter
  6 +import random
  7 +
  8 +
  9 +# 随机字符
  10 +def rndChar():
  11 + num = 0
  12 + while num == 0 and ((num >= 58 and num <= 64) or (num >= 91 and num <= 96)):
  13 + num = random.randint(48, 122)
  14 + return num
  15 +
  16 +# 随机颜色
  17 +
  18 +
  19 +def rndColor():
  20 + return ''
@@ -5,6 +5,7 @@ deploy_ip_host = "172.26.40.105:8840" @@ -5,6 +5,7 @@ deploy_ip_host = "172.26.40.105:8840"
5 # 系统数据库 5 # 系统数据库
6 SQLALCHEMY_DATABASE_URI = "postgresql://postgres:chinadci@172.26.60.101:5432/dmap_manager" 6 SQLALCHEMY_DATABASE_URI = "postgresql://postgres:chinadci@172.26.60.101:5432/dmap_manager"
7 7
  8 +
8 # 指定精华表所在位置(必须为空间库),设置为None则存放在各自的实体库中 9 # 指定精华表所在位置(必须为空间库),设置为None则存放在各自的实体库中
9 #VACUATE_DB_URI = None 10 #VACUATE_DB_URI = None
10 VACUATE_DB_URI = SQLALCHEMY_DATABASE_URI 11 VACUATE_DB_URI = SQLALCHEMY_DATABASE_URI
@@ -15,6 +16,8 @@ tile_engine = "http://172.26.99.160:8820" @@ -15,6 +16,8 @@ tile_engine = "http://172.26.99.160:8820"
15 vector_engine = "http://172.26.99.160:8820" 16 vector_engine = "http://172.26.99.160:8820"
16 17
17 # 固定配置不需要修改 18 # 固定配置不需要修改
  19 +
  20 +swagger_configure = {"title": "DMapManager"}
18 entry_data_thread = 3 21 entry_data_thread = 3
19 SECRET_KEY = b'_5#y2L"F4Q8z\n\xec]/' 22 SECRET_KEY = b'_5#y2L"F4Q8z\n\xec]/'
20 # 权限 23 # 权限
  1 +101映射域名
  2 +dmap.apps.chinadci.com
  3 +# 鉴权
  4 +Authlib
  5 +## 1 授权服务器
  6 +为授权、颁发令牌、刷新令牌和撤销令牌提供多个端点。当资源拥有者(用户)获得授权时,授权服务器会向客户端颁发访问令牌。
  7 +### 资源拥有者:用户
  8 +### 客户端:客户端是一个代表资源拥有者并在授权情况下请求受保护资源的应用
  9 + * client_id是唯一标识
  10 + * client_secret是密码
  11 + * 客户端令牌端点认证方法
  12 +### 令牌
  13 +使用令牌访问用户资源,令牌发布时带有有效期,有访问范围等等。它至少包括:
  14 +* access_token
  15 +* refresh_token
  16 +*...
  17 +### 服务器
  18 +authlib使用工具AuthorizationServer管理请求和响应
  19 +
  20 +
  21 +
  22 +# Web安全
  23 +## 1 接口权限控制
  24 +[swagger](https://swagger.io/docs/specification/2-0/what-is-swagger/)
  25 +
  26 +**需求:api需要授权**
  27 +
  28 +1.确定当前使用openapi2版本
  29 +2.了解简单YAML使用方式,文档使用YAML格式
  30 +3.声明Swagger,传入配置template(json或者yaml)
  31 +```python
  32 +Swagger(app, config=swagger_config,template=SWAGGER_TEMPLATE)
  33 +```
  34 +
  35 +## 2 用户密码加密
  36 +[pipy](https://pypi.org/project/gmssl/)
  37 +[github](https://github.com/guanzhi/GmSSL)
  38 +[使用gmssl demo](https://www.cnblogs.com/rocedu/p/15518988.html)
  39 +
  40 +**用户密码加密不可逆,兼容国产化,使用sm3算法,采用gmssl开源组件**
  41 +
  42 +封装好的类使用如下:
  43 +```python
  44 +from app.models import SM3
  45 +password = SM3.encode('test')
  46 +```
  47 +## 3 通过网络传输的敏感信息要加密
  48 +~~使用sm2,通过gmssl工具生成sm2的公钥、私钥。~~
  49 +~~[教程](https://github.com/guanzhi/GmSSL)~~
  50 +
  51 +~~1.生成sm2公钥、私钥~~
  52 +~~privatekey使用的pem是`zhou@123`~~
  53 +
  54 +~~2. 使用公钥加密,私钥解密~~
  55 +~~前端使用sm-crypto,用户与python-gmssl互通~~
  56 +~~[npm_sm-crypto](https://www.npmjs.com/package/sm-crypto)~~
  57 +
  58 +使用AES对称加密敏感信息,前端加密,后端解密。偏移量iv、加密密钥key与前端保持一致,保证解密正确。封装在models.py中。
  59 +
  60 +依赖组件:
  61 +* pycryptodome
  62 +* Crypto
  63 +* binascii
  64 +参考资料
  65 +[pycryptodome]()
  66 +
  67 +**demo**
  68 +```python
  69 +from app.models import AESHelper
  70 +
  71 +encryption=AESHelper.encode('test_data')
  72 +result=AESHelper.decode(encryption)
  73 +```
  74 +
  75 +## 4 使用验证码,防止恶意破解密码、刷票、论坛灌水、刷页
  76 +验证码又叫CAPTCHA
  77 +
  78 +[验证码基础知识](https://baike.baidu.com/item/%E9%AA%8C%E8%AF%81%E7%A0%81/31701)
  79 +[使用python图像处理标准库](https://www.liaoxuefeng.com/wiki/1016959663602400/1017785454949568)
  80 +[pillow](https://pillow.readthedocs.io/en/stable/index.html)
@@ -17,3 +17,5 @@ kazoo==2.8.0 @@ -17,3 +17,5 @@ kazoo==2.8.0
17 paramiko==2.8.0 17 paramiko==2.8.0
18 requests==2.26.0 18 requests==2.26.0
19 schedule==1.1.0 19 schedule==1.1.0
  20 +gmssl==3.2.1
  21 +pycryptodome==3.13.0
注册登录 后发表评论