|
|
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 |
...
|
...
|
|