提交 978f7fa2a3737508c283610453f1d682becb358a

作者 nheweijun
2 个父辈 f54eb3c0 dac245db
  1 +from datetime import datetime
1 2 from logging import error
2 3 from flasgger import swag_from
3 4 from app.util import BlueprintApi
... ... @@ -6,7 +7,7 @@ from .models import *
6 7 from .oauth2 import authorization, generate_user_info, require_oauth
7 8 from authlib.oauth2 import OAuth2Error
8 9 from authlib.integrations.flask_oauth2 import current_token
9   -from . import user_create, client_create, client_query, user_query, user_update, user_delete
  10 +from . import user_create, client_create, client_query, user_query, user_update, user_delete, auth_log_query
10 11 import configure
11 12 from app.decorators.auth_decorator import auth_decorator
12 13 import time
... ... @@ -15,7 +16,8 @@ from app.util.component.StructurePrint import StructurePrint
15 16 import traceback
16 17 # from oauthlib import oauth2
17 18 import requests
18   -from app.modules.auth.models import OAuth2Token, User, db
  19 +from app.modules.auth.models import OAuth2Token, User, db, OAuthLog
  20 +from app.util.enum.AuthEnum import AuthEnum, OriginEnum, OperateEnum
19 21
20 22
21 23 def current_user():
... ... @@ -35,6 +37,16 @@ def split_by_crlf(s):
35 37 return [v for v in s.splitlines() if v]
36 38
37 39
  40 +def getRedirectUrl(request): # 获取重定向地址
  41 + # 获取头部信息
  42 + X_Forwarded_Proto = request.headers.get("X-Forwarded-Proto") # 协议
  43 + X_Forwarded_Host = request.headers.get("X-Forwarded-Host") # host
  44 + if not X_Forwarded_Proto == None and not X_Forwarded_Host == None:
  45 + return X_Forwarded_Proto+"://"+X_Forwarded_Host
  46 + else:
  47 + return request.host_url.rstrip("/")
  48 +
  49 +
38 50 class DataManager(BlueprintApi):
39 51 bp = Blueprint("Auth", __name__, url_prefix="/auth")
40 52
... ... @@ -45,7 +57,7 @@ class DataManager(BlueprintApi):
45 57 request2 = authorization.create_oauth2_request(request)
46 58 grant2 = authorization.get_authorization_grant(request=request2)
47 59 redirect_uri = grant2.validate_authorization_request()
48   - session["redirect_uri"] = redirect_uri
  60 + session["redirect_uri"] = redirect_uri # 记录跳转重定向地址
49 61 if request.method == "GET":
50 62 # 没有登录,跳转到登录界面
51 63 try:
... ... @@ -71,8 +83,11 @@ class DataManager(BlueprintApi):
71 83 crypt_pwd = request.form.get("password")
72 84 # password = SM3.encode(crypt_pwd)
73 85 password = SM3.encode(AESHelper.decode(crypt_pwd))
  86 +
  87 + # 仅支持dmap平台保留用户登录
  88 + origin_type = OriginEnum.Dmap.name.lower()
74 89 user = User.query.filter_by(
75   - username=username, password=password).first()
  90 + username=username, password=password, origin=origin_type).first()
76 91 if not user:
77 92 error = "账号或密码不正确"
78 93 flash(error)
... ... @@ -83,6 +98,17 @@ class DataManager(BlueprintApi):
83 98 if user:
84 99 session["id"] = user.id
85 100 grant_user = user
  101 +
  102 + # 日志
  103 + log = OAuthLog(user_id=user.id, username=user.username,
  104 + auth_type=AuthEnum.Other.name.lower(),
  105 + message="认证成功", create_time=datetime.now(),
  106 + operate_type=OperateEnum.Login,
  107 + displayname=user.displayname, ip=request.remote_addr
  108 + )
  109 + db.session.add(log)
  110 + db.session.commit()
  111 +
86 112 return authorization.create_authorization_response(request=request, grant_user=grant_user)
87 113
88 114 # try:
... ... @@ -116,16 +142,34 @@ class DataManager(BlueprintApi):
116 142 def logout():
117 143 try:
118 144 request2 = authorization.create_oauth2_request(request)
119   - grant1 = authorization.get_authorization_grant(request=request2)
  145 + grant1 = authorization.get_authorization_grant(
  146 + request=request2)
120 147 redirect_uri = grant1.validate_authorization_request()
121 148 access_token = request.args.get("accesstoken")
122   - accesstoken = OAuth2Token.query.filter_by(
123   - access_token=access_token).first()
124   - accesstoken.revoked = True
125   - db.session.commit()
126   - remove_user()
  149 +
  150 + if not access_token == None:
  151 + accesstoken = OAuth2Token.query.filter_by(
  152 + access_token=access_token).one_or_none()
  153 + if not accesstoken == None:
  154 + accesstoken.revoked = True
  155 + db.session.commit()
  156 + if current_user() != None:
  157 + remove_user()
  158 +
  159 + user = User.query.get(accesstoken.user_id)
  160 + # 日志
  161 + if user != None:
  162 + log = OAuthLog(user_id=user.id, username=user.username,
  163 + auth_type=AuthEnum.Other.name.lower(),
  164 + message="注销成功", create_time=datetime.now(),
  165 + operate_type=OperateEnum.Logout, token=access_token,
  166 + displayname=user.displayname, ip=request.remote_addr
  167 + )
  168 + db.session.add(log)
  169 + db.session.commit()
  170 +
127 171 except OAuth2Error as error:
128   - return jsonify(dict(error.get_body()))
  172 + StructurePrint().print(error.__str__()+":" + traceback.format_exc(), "error")
129 173 return redirect(redirect_uri)
130 174
131 175 """接口"""
... ... @@ -207,15 +251,15 @@ class DataManager(BlueprintApi):
207 251 except Exception as e:
208 252 StructurePrint().print(e.__str__()+":" + traceback.format_exc(), "error")
209 253
210   - @staticmethod
211   - @bp.route("/translate", methods=["GET"])
212   - def translate():
213   - password = ['esri@123', 'admin', 'DMap@123', 'passwd']
214   - result = {}
215   - for p in password:
216   - new_pwd = SM3.encode(p)
217   - result[p] = new_pwd
218   - return result
  254 + # @staticmethod
  255 + # @bp.route("/translate", methods=["GET"])
  256 + # def translate():
  257 + # password = ['esri@123', 'admin', 'DMap@123', 'passwd','dci112..']
  258 + # result = {}
  259 + # for p in password:
  260 + # new_pwd = SM3.encode(p)
  261 + # result[p] = new_pwd
  262 + # return result
219 263
220 264 '''
221 265 三方登录:OA
... ... @@ -226,8 +270,9 @@ class DataManager(BlueprintApi):
226 270 client = oauth2.WebApplicationClient(
227 271 configure.OA["client_id"])
228 272 state = client.state_generator()
  273 + StructurePrint().print(request.headers, "info")
229 274 auth_uri = client.prepare_request_uri(
230   - configure.OA["authorization_endpoint"], configure.OA["redirect_uri"], configure.OA["scope"], state)
  275 + configure.OA["authorization_endpoint"], getRedirectUrl(request) + configure.OA["redirect_uri"], configure.OA["scope"], state)
231 276 session["oauth_state"] = state
232 277 return redirect(auth_uri)
233 278
... ... @@ -237,78 +282,111 @@ class DataManager(BlueprintApi):
237 282 @staticmethod
238 283 @bp.route("/oa/callback", methods=["GET"])
239 284 def oa_callback():
  285 + try:
  286 + auth_default_redirect_uri = configure.auth_default_redirect_uri
  287 + client = oauth2.WebApplicationClient(
  288 + configure.OA["client_id"])
  289 +
  290 + # 获取code
  291 + code = client.parse_request_uri_response(
  292 + request.url, session["oauth_state"]).get("code")
  293 +
  294 + if code == None:
  295 + return "登录失败"
  296 +
  297 + # 获取token
  298 + body = client.prepare_request_body(
  299 + code, redirect_uri=getRedirectUrl(request) + configure.OA["redirect_uri"], client_secret=configure.OA["client_secret"])
  300 +
  301 + r = requests.post(configure.OA["token_endpoint"], body, headers={
  302 + "Content-Type": "application/x-www-form-urlencoded"})
  303 +
  304 + tokeninfo = r.json()
  305 + access_token = tokeninfo.get("access_token")
  306 + id_token = tokeninfo.get("id_token")
  307 +
  308 + origin_type = "dci_oa" # 三方登录标识
  309 + if access_token:
  310 + # 获取用户信息
  311 + userinfo_url = configure.OA["userinfo_endpoint"]
  312 + user_request = requests.get(userinfo_url, headers={
  313 + "Authorization": "Bearer %s" % access_token})
  314 + userinfo = user_request.json()
  315 + user_name = userinfo.get("user_name")
  316 + display_name = userinfo.get("displayname")
  317 + display_name = display_name.split(
  318 + )[-1] if display_name != None else user_name
  319 +
  320 + # 默认关联dmap用户
  321 + try:
  322 + user = User.query.filter_by(
  323 + username=user_name, origin=origin_type).first()
  324 + except error as e:
  325 + user = None
  326 +
  327 + # 用户不存在,创建用户
240 328
241   - client = oauth2.WebApplicationClient(
242   - configure.OA["client_id"])
243   -
244   - # 获取code
245   - code = client.parse_request_uri_response(
246   - request.url, session["oauth_state"]).get("code")
247   -
248   - if code == None:
249   - return "登录失败"
250   -
251   - # 获取token
252   - body = client.prepare_request_body(
253   - code, redirect_uri=configure.OA["redirect_uri"], client_secret=configure.OA["client_secret"])
254   -
255   - r = requests.post(configure.OA["token_endpoint"], body, headers={
256   - "Content-Type": "application/x-www-form-urlencoded"})
257   -
258   - tokeninfo = r.json()
259   - access_token = tokeninfo.get("access_token")
260   -
261   - if access_token:
262   - # 获取用户信息
263   - userinfo_url = configure.OA["userinfo_endpoint"]
264   - user_request = requests.get(userinfo_url, headers={
265   - "Authorization": "Bearer %s" % access_token})
266   - userinfo = user_request.json()
267   - user_name = userinfo.get("user_name")
268   - display_name = userinfo.get("displayname")
269   -
270   - # 默认关联dmap用户
271   - try:
272   - user = User.query.filter_by(
273   - username=user_name).first()
274   - except error as e:
275   - user = None
  329 + if not user:
  330 + user = User(username=user_name, password=SM3.encode('DMap@123'), role='dataman',
  331 + phone='', company='', position='', email='', displayname=display_name,
  332 + origin=origin_type,
  333 + create_time=time.strftime(
  334 + "%Y-%m-%d %H:%M:%S", time.localtime()),
  335 + update_time=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
  336 + db.session.add(user)
  337 + db.session.commit()
  338 +
  339 + session["id"] = user.id
  340 +
  341 + # dmap token授权
  342 + # 存入数据库
  343 + token = OAuth2Token(
  344 + client_id=configure.OA["client_id"],
  345 + token_type=tokeninfo.get("token_type"),
  346 + access_token=access_token,
  347 + scope=tokeninfo.get("scope"),
  348 + expires_in=tokeninfo.get("expires_in"),
  349 + user_id=user.id
  350 + )
  351 +
  352 + db.session.add(token)
  353 + db.session.commit()
276 354
277   - # 用户不存在,创建用户
278   - if not user:
279   - user = User(username=user_name, password=SM3.encode('DMap@123'), role='dataman',
280   - phone='', company='', position='', email='',
281   - create_time=time.strftime(
282   - "%Y-%m-%d %H:%M:%S", time.localtime()),
283   - update_time=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
284   - db.session.add(user)
  355 + redirect_uri = session["redirect_uri"] if "redirect_uri" in session else auth_default_redirect_uri
  356 +
  357 + #session["id_token"] = id_token
  358 + response = make_response(redirect(redirect_uri))
  359 + response.set_cookie('accessToken', access_token,
  360 + max_age=configure.expiretime)
  361 + response.set_cookie('id_token', id_token,
  362 + max_age=configure.expiretime)
  363 +
  364 + log = OAuthLog(user_id=user.id, username=user_name,
  365 + auth_type=AuthEnum.Other.name.lower(),
  366 + message="三方认证成功", create_time=datetime.now(),
  367 + operate_type=OperateEnum.Login, token=access_token,
  368 + displayname=display_name, ip=request.remote_addr)
  369 + db.session.add(log)
285 370 db.session.commit()
286 371
287   - # dmap token授权
288   - session["id"] = user.id
  372 + return response
  373 + else:
  374 + raise Exception("缺少access_token")
289 375
290   - # 存入数据库
291   - token = OAuth2Token(
292   - client_id=configure.OA["client_id"],
293   - token_type=tokeninfo.get("token_type"),
294   - access_token=access_token,
295   - scope=tokeninfo.get("scope"),
296   - expires_in=tokeninfo.get("expires_in"),
297   - user_id=user.id
298   - )
299   - db.session.add(token)
300   - db.session.commit()
301   - redirect_uri = ""
302   - try:
303   - redirect_uri = session["redirect_uri"]
304   - if not redirect_uri:
305   - redirect_uri = '/'
306   - except:
307   - redirect_uri = "/"
308   -
309   - response = make_response(redirect(redirect_uri))
310   - response.set_cookie('accessToken', access_token, max_age=604_800)
311   -
312   - return response
313   - else:
314   - return redirect('/')
  376 + except Exception as e:
  377 + StructurePrint().print(e.__str__()+":" + traceback.format_exc(), "error")
  378 + pop_list = ["id", "redirect_uri"]
  379 + for p in pop_list:
  380 + if p in session:
  381 + session.pop(p)
  382 + return redirect(auth_default_redirect_uri)
  383 +
  384 + @staticmethod
  385 + @bp.route("/logs", methods=["GET"])
  386 + @swag_from(auth_log_query.Api.api_doc)
  387 + @auth_decorator(configure.UserPermission)
  388 + def authLog():
  389 + '''
  390 + 登录日志
  391 + '''
  392 + return auth_log_query.Api().result
... ...
  1 +# coding=utf-8
  2 +# author: qianyingz
  3 +# createtime: 2022/03/09
  4 +# email: qianyingz@chinadci.com
  5 +from tokenize import String
  6 +from numpy import number
  7 +from sqlalchemy import or_
  8 +from .models import *
  9 +from app.util.component.ApiTemplate import ApiTemplate
  10 +import json
  11 +
  12 +
  13 +class Api(ApiTemplate):
  14 + api_name = "登录日志"
  15 +
  16 + def para_check(self):
  17 + pass
  18 +
  19 + def process(self):
  20 + # 返回结果
  21 + res = {}
  22 + res["result"] = False
  23 + try:
  24 + # 业务逻辑
  25 + page_index = int(self.para.get("page_index", "0"))
  26 + page_size = int(self.para.get("page_size", "1000"))
  27 + # name = self.para.get("name")
  28 + order_by = self.para.get("order_by")
  29 + filter_param = self.para.get("filter_param", "")
  30 + filter_param_json = {} if filter_param == "" else json.loads(
  31 + filter_param)
  32 + kw = filter_param_json["kw"] if "kw" in filter_param_json else None
  33 + type = filter_param_json["type"] if "type" in filter_param_json else None
  34 +
  35 + log_query = OAuthLog.query
  36 +
  37 + if kw != None:
  38 + if isinstance(kw, str):
  39 + filter_username_query = log_query.filter(OAuthLog.username.like(
  40 + "%" + kw + "%"))
  41 + filter_display_query = log_query.filter(
  42 + OAuthLog.displayname.like("%" + kw + "%"))
  43 + log_query = filter_username_query.union(
  44 + filter_display_query)
  45 +
  46 + if type != None:
  47 + if isinstance(type, (str,int)):
  48 + log_query = log_query.filter(OAuthLog.operate_type == type)
  49 + elif isinstance(type, list):
  50 + log_query = log_query.filter(OAuthLog.operate_type.in_(type))
  51 +
  52 + log_query = log_query.order_by(OAuthLog.create_time.desc())
  53 +
  54 + count = log_query.count()
  55 + logs = log_query.limit(page_size).offset(
  56 + page_index*page_size).all()
  57 +
  58 + res["data"] = {"count": count,
  59 + "list": list(map(lambda t:
  60 + {"id": t.id, "username": t.username, "ip": t.ip,
  61 + "message": t.message, "create_time": t.create_time.strftime("%Y-%m-%d %H:%M:%S"),
  62 + "operate_type": t.operate_type,
  63 + "auth_type": t.auth_type,
  64 + "displayname": t.displayname}, logs))}
  65 +
  66 + # # 获取集合
  67 + # userLinq = User.query.order_by(User.id.desc())
  68 + # if name:
  69 + # userLinq = userLinq.filter(
  70 + # User.username.like("%" + name + "%"))
  71 + # tmp_count = userLinq.count()
  72 + # tmp_list = userLinq.limit(page_size).offset(
  73 + # page_index * page_size).all()
  74 + # res["data"] = {
  75 + # "count": tmp_count,
  76 + # "list": list(map(lambda t:
  77 + # {"guid": t.id, "username": t.username,
  78 + # "role": t.role, "display_name": t.display_name,
  79 + # "status": t.status},
  80 + # tmp_list))}
  81 +
  82 + res["result"] = True
  83 +
  84 + except Exception as e:
  85 + raise e
  86 + return res
  87 +
  88 + api_doc = {
  89 + "tags": ["登录日志"],
  90 + "parameters": [
  91 + {"name": "page_index",
  92 + "in": "query",
  93 + "type": "int",
  94 + "description": "当前页",
  95 + "default": 0},
  96 + {"name": "page_size",
  97 + "in": "query",
  98 + "type": "int",
  99 + "description": "条数",
  100 + "default": 1000},
  101 + {"name": "order_by",
  102 + "in": "query",
  103 + "type": "string",
  104 + "description": "排序"},
  105 + {"name": "filter_param",
  106 + "in": "query",
  107 + "type": "json",
  108 + "description": "过滤"}
  109 + ],
  110 + "responses": {
  111 + 200: {
  112 + "schema": {
  113 + "properties": {
  114 + }
  115 + }
  116 + }
  117 + }
  118 + }
... ...
1   -from flask_sqlalchemy import sqlalchemy
2   -from sqlalchemy import Column, Integer, Text, Time, ForeignKey
  1 +from sqlalchemy import Column, Integer, Text, Time, ForeignKey, DateTime
3 2 from app.models import db
4 3 from authlib.integrations.sqla_oauth2 import (
5 4 OAuth2ClientMixin,
... ... @@ -7,6 +6,7 @@ from authlib.integrations.sqla_oauth2 import (
7 6 OAuth2AuthorizationCodeMixin
8 7 )
9 8 from sqlalchemy.orm import relationship
  9 +from app.util.enum.AuthEnum import OriginEnum,UserStatusEnum
10 10
11 11
12 12 class User (db.Model):
... ... @@ -16,17 +16,18 @@ class User (db.Model):
16 16 __tablename__ = "dmap_user"
17 17 id = Column(Integer, primary_key=True)
18 18 username = Column(Text)
19   -
20 19 password = Column(Text)
21 20 company = Column(Text)
22 21 position = Column(Text)
23 22 phone = Column(Text)
24 23 email = Column(Text)
25   - create_time = Column(Time)
26   - update_time = Column(Time)
  24 + create_time = Column(DateTime)
  25 + update_time = Column(DateTime)
27 26 role = Column(Text)
28   - #display_name = Column(Text, nullable=True) # 昵称
29   - #origin = Column(Text, default="dmap") # 用户来源,默认dmap平台用户
  27 + displayname = Column(Text, nullable=True) # 昵称
  28 + # 用户来源,默认dmap平台用户
  29 + origin = Column(Text, default=OriginEnum.Dmap.name.lower())
  30 + status = Column(Integer, default=UserStatusEnum.Active) # 1:激活,2:冻结,0:注销
30 31
31 32 def __str__(self):
32 33 return self.username
... ... @@ -68,3 +69,26 @@ class OAuth2Token(db.Model, OAuth2TokenMixin):
68 69 Integer, ForeignKey('dmap_user.id', ondelete='CASCADE'))
69 70 # name = Column(Text)
70 71 user = relationship('User')
  72 +
  73 +
  74 +'''
  75 +认证日志
  76 +'''
  77 +
  78 +# 认证日志
  79 +
  80 +
  81 +class OAuthLog(db.Model):
  82 + __tablename__ = "dmap_oauth_log"
  83 +
  84 + id = Column(Integer, primary_key=True)
  85 + user_id = Column(Text, nullable=False)
  86 + username = Column(Text) # 用户输入账号
  87 + displayname=Column(Text) # 昵称
  88 + ip = Column(Text)
  89 + # 登录方式:password,三方登录
  90 + auth_type = Column(Text)
  91 + message = Column(Text) # 登录返回提示
  92 + create_time = Column(DateTime) # 记录创建时间
  93 + operate_type = Column(Integer, nullable=False) # 操作类型,登录,注销
  94 + token = Column(Text)
... ...
... ... @@ -51,7 +51,7 @@ def exists_nonce(nonce, req):
51 51
52 52
53 53 def generate_user_info(user, scope):
54   - return UserInfo(sub=str(user.id), name=user.username, role=user.role, company=user.company)
  54 + return UserInfo(sub=str(user.id), name=user.username, role=user.role, company=user.company, display_name=user.displayname, status=user.status)
55 55
56 56
57 57 def create_authorization_code(client, grant_user, request):
... ...
... ... @@ -27,18 +27,19 @@ class Api(ApiTemplate):
27 27 res["result"] = False
28 28 try:
29 29 # 业务逻辑
30   - username = AESHelper.decode( self.para.get("username", ''))
  30 + username = AESHelper.decode(self.para.get("username", ''))
31 31 password = SM3.encode(AESHelper.decode(self.para.get("pwd", '')))
32 32 role = AESHelper.decode(self.para.get("role", ''))
33 33 company = AESHelper.decode(self.para.get("company", ''))
34 34 position = AESHelper.decode(self.para.get("position", ''))
35 35 email = AESHelper.decode(self.para.get("email", ''))
36 36 phone = AESHelper.decode(self.para.get("phone", ''))
  37 + displayname = username
37 38 # 是否重名
38 39 if(User.query.filter_by(username=username).one_or_none()):
39 40 res["msg"] = "username 已存在"
40 41 else:
41   - user = User(username=username, password=password, role=role,
  42 + user = User(username=username, displayname=displayname, password=password, role=role,
42 43 phone=phone, company=company, position=position, email=email,
43 44 create_time=time.strftime(
44 45 "%Y-%m-%d %H:%M:%S", time.localtime()),
... ...
... ... @@ -20,7 +20,6 @@ class Api(ApiTemplate):
20 20 res["result"] = False
21 21 try:
22 22 # 业务逻辑
23   - pass
24 23 page_index = int(self.para.get("page_index", "0"))
25 24 page_size = int(self.para.get("page_size", "1000"))
26 25 name = self.para.get("name")
... ... @@ -31,7 +30,8 @@ class Api(ApiTemplate):
31 30 res["data"] = {"guid": tmp_user.id, "username": tmp_user.username,
32 31 "role": tmp_user.role, "company": tmp_user.company,
33 32 "position": tmp_user.position, "email": tmp_user.email,
34   - "phone": tmp_user.phone}
  33 + "phone": tmp_user.phone, "display_name": tmp_user.displayname,
  34 + "status": tmp_user.status}
35 35 else:
36 36 # 获取集合
37 37 userLinq = User.query.order_by(User.id.desc())
... ... @@ -45,7 +45,8 @@ class Api(ApiTemplate):
45 45 "count": tmp_count,
46 46 "list": list(map(lambda t:
47 47 {"guid": t.id, "username": t.username,
48   - "role": t.role},
  48 + "role": t.role, "display_name": t.displayname,
  49 + "status": t.status},
49 50 tmp_list))}
50 51 res["result"] = True
51 52
... ...
... ... @@ -55,7 +55,7 @@ class Api(ApiTemplate):
55 55 {"name": "database_guid",
56 56 "in": "formData",
57 57 "type": "string",
58   - "description": "数据库guid", "": "true"},
  58 + "description": "数据库guid", "required": "true"},
59 59
60 60 ],
61 61 "responses":{
... ...
... ... @@ -238,4 +238,28 @@ button {
238 238 -webkit-box-sizing: border-box;
239 239 -moz-box-sizing: border-box;
240 240 box-sizing: border-box;
  241 +}
  242 +
  243 +.other-mod {
  244 + margin-top: 35px;
  245 +}
  246 +
  247 +.other-mod .other-tit {
  248 + color: #999;
  249 + display: inline-block;
  250 + margin-right: 20px;
  251 +}
  252 +
  253 +.other-mod .other-link {
  254 + text-align: right;
  255 + margin-left: 20px;
  256 + float: right;
  257 +}
  258 +
  259 +.other-mod .other-link a {
  260 + color: #545454;
  261 +}
  262 +
  263 +.other-mod .other-link:hover a {
  264 + color: #3081c3;
241 265 }
\ No newline at end of file
... ...
... ... @@ -76,8 +76,13 @@
76 76 立即登录
77 77 </button>
78 78 </div>
79   - <div>——或者——</div>
80   - <a href="/auth/oa"> 城信所统一用户认证 </a>
  79 +
  80 + <div class="form-group other-mod">
  81 + <div class="other-tit"><span>其他登录方式</span></div>
  82 + <div class="other-link">
  83 + <a href="/auth/oa">城信所统一用户认证</a>
  84 + </div>
  85 + </div>
81 86 </form>
82 87 </div>
83 88 <div class="clear"></div>
... ...
  1 +from enum import Enum,IntEnum
  2 +
  3 +'''
  4 +认证方式
  5 +'''
  6 +
  7 +
  8 +class AuthEnum(IntEnum):
  9 + Password = 1 # 账号密码登录,包括三方的账号密码登录
  10 + Other = 3 # 三方登录
  11 +
  12 +
  13 +'''
  14 +用户来源
  15 +'''
  16 +
  17 +
  18 +class OriginEnum(IntEnum):
  19 + Dmap = 1
  20 +
  21 +
  22 +'''用户状态'''
  23 +
  24 +
  25 +class UserStatusEnum(IntEnum):
  26 + Cancellation = 0, # 注销
  27 + Active = 1, # 活跃
  28 + Freeze = 2 # 冻结
  29 +
  30 +
  31 +class OperateEnum(IntEnum):
  32 + Login = 1, # 登录
  33 + Logout = 2 # 注销
... ...
... ... @@ -27,13 +27,17 @@ ServicePermission = ['admin', 'dataman', 'publisher']
27 27
28 28 log_level = logging.INFO
29 29
  30 +expiretime = 604_800 # 7天
30 31
31 32 OA = {
32 33 "client_id": "dmap",
33 34 "client_secret": "secret",
34 35 "scope": "openid profile",
35   - "redirect_uri": "http://localhost:8841/auth/oa/callback",
  36 + "redirect_uri": "/auth/oa/callback",
36 37 "authorization_endpoint": "https://login.chinadci.com/netsso/connect/authorize",
37 38 "token_endpoint": "https://login.chinadci.com/netsso/connect/token",
38   - "userinfo_endpoint": "https://login.chinadci.com/netsso/connect/userinfo"
  39 + "userinfo_endpoint": "https://login.chinadci.com/netsso/connect/userinfo",
  40 + "end_session_endpoint": "https://login.chinadci.com/netsso/connect/endsession"
39 41 }
  42 +
  43 +auth_default_redirect_uri="http://localhost:9999"
\ No newline at end of file
... ...
... ... @@ -77,4 +77,8 @@ result=AESHelper.decode(encryption)
77 77
78 78 [验证码基础知识](https://baike.baidu.com/item/%E9%AA%8C%E8%AF%81%E7%A0%81/31701)
79 79 [使用python图像处理标准库](https://www.liaoxuefeng.com/wiki/1016959663602400/1017785454949568)
80   -[pillow](https://pillow.readthedocs.io/en/stable/index.html)
\ No newline at end of file
  80 +[pillow](https://pillow.readthedocs.io/en/stable/index.html)
  81 +
  82 +
  83 +## 5 使用编译文件的方法
  84 +cmd下运行./compile.py
... ...
注册登录 后发表评论