auth.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. # -*- coding: utf-8 -*-
  2. from fastapi import APIRouter, Depends, Request, Header, Form, Body
  3. from fastapi.responses import FileResponse, StreamingResponse
  4. from sqlalchemy.orm import Session
  5. from fastapi.responses import JSONResponse
  6. from database import get_db
  7. from utils import *
  8. from utils.vcode import *
  9. from utils.redis_util import *
  10. import base64
  11. from common.const import *
  12. from io import BytesIO
  13. from utils.StripTagsHTMLParser import *
  14. from common import security
  15. from datetime import timedelta
  16. from common.security import verify_password
  17. from utils import ase_utils
  18. from common.auth_user import *
  19. from common import YzyApi
  20. from models import *
  21. from urllib.parse import quote
  22. import requests
  23. import traceback
  24. router = APIRouter()
  25. @router.get('/tenant/list')
  26. async def tenant_list(
  27. request: Request,
  28. db: Session = Depends(get_db)
  29. ):
  30. return {
  31. "code": 200,
  32. "msg": "操作成功",
  33. "data": {
  34. "tenantEnabled": False,
  35. "voList": []
  36. }
  37. }
  38. def buildVerificationCodeRedisKey(uuid: str) -> str:
  39. return VERIFICATION_CODE_REDIS_PREFIX.format(uuid)
  40. @router.get('/code')
  41. async def code(
  42. request: Request,
  43. db: Session = Depends(get_db)
  44. ):
  45. uuid_str = md5(new_guid())
  46. image, code = getVerifyCode()
  47. buf = BytesIO()
  48. image.save(buf, 'png')
  49. img_data = buf.getvalue()
  50. image_bytes_io = BytesIO(img_data)
  51. image_bytes_io.seek(0)
  52. image_bytes = image_bytes_io.read()
  53. base64_str = base64.b64encode(image_bytes).decode('utf-8')
  54. redis_key = "kaptcha_" + buildVerificationCodeRedisKey(uuid_str)
  55. redis_set(redis_key, code)
  56. return {
  57. "code": 200,
  58. "msg": "操作成功",
  59. "data": {
  60. "captchaEnabled": True,
  61. "uuid": uuid_str,
  62. "img": base64_str
  63. }
  64. }
  65. @router.post('/login')
  66. async def login(
  67. request: Request,
  68. db: Session = Depends(get_db),
  69. data: dict = Depends(remove_xss_json)
  70. ):
  71. try:
  72. # tenantId = data['tenantId']
  73. username = data['username']
  74. password = data['password']
  75. # rememberMe = data['rememberMe']
  76. uuid_str = data['uuid']
  77. code = data['code']
  78. # clientId = data['clientId']
  79. # grantType = data['grantType']
  80. # 仅为了可能的兼容
  81. clientId = "e5cd7e4891bf95d1d19206ce24a7b32e"
  82. grantType = "password"
  83. uuid = buildVerificationCodeRedisKey(uuid_str)
  84. redis_key = "kaptcha_" + uuid
  85. redis_code = redis_get(redis_key)
  86. if code is None or code != redis_code:
  87. return {
  88. "code": 500,
  89. "msg": "图片验证码不正确",
  90. }
  91. redis_login_key = "login_user_" + username
  92. login_error_times = redis_get(redis_login_key)
  93. if login_error_times is None:
  94. login_error_times = 0
  95. else:
  96. login_error_times = int(login_error_times)
  97. if login_error_times >= 5:
  98. return {
  99. "code": 500,
  100. "msg": "登录错误多,请5分钟后再尝试!",
  101. }
  102. password = ase_utils.aesDecrypt(uuid_str, password)
  103. logger.info('userpass: {}', password)
  104. row = db.query(SysUser).filter(SysUser.user_name == username).first()
  105. if row is None:
  106. login_error_times = login_error_times + 1
  107. redis_set_with_time(redis_login_key, str(login_error_times), 300)
  108. return JSONResponse(status_code=404, content={"code": 404, "msg": "帐号或者密码错误"})
  109. # return {
  110. # "error": 1,
  111. # "errmsg": "帐号或者密码错误",
  112. # }
  113. logger.info('row.password: {}', row.password)
  114. if verify_password(password, row.password) == False:
  115. login_error_times = login_error_times + 1
  116. redis_set_with_time(redis_login_key, str(login_error_times), 300)
  117. return JSONResponse(status_code=404, content={"code":404,"msg":"帐号或者密码错误"})
  118. '''
  119. m = hashlib.md5()
  120. m.update(userpass.encode('utf-8'))
  121. password_md5 = m.hexdigest()
  122. password_db = row.password
  123. if password_md5 != password_db:
  124. login_error_times = login_error_times + 1
  125. redis_set_with_time(redis_login_key, str(login_error_times), 300)
  126. return {
  127. "error": 1,
  128. "errmsg": "帐号或者密码错误",
  129. }
  130. # 校验长期(超过1个月)未使用的账号和及开通后未及时(如72小时)修改初始密码的账号做清除
  131. last_login_time = datetime.fromtimestamp(row.last_login_time)
  132. if row.login == 0:
  133. # 计算初始化的时间和当前时间相差的小时数
  134. diff_hour = (datetime.now() - last_login_time).seconds/3600
  135. if diff_hour > 72:
  136. return {
  137. "error": 1,
  138. "errmsg": "你的账号在开通后(72小时)内未登录及修改初始密码,账号已被锁定,请联系管理员处理,否则将被清除。",
  139. }
  140. else:
  141. # 计算上次登录到当前时间的相差天数
  142. diff_day = (datetime.now() - last_login_time).days
  143. if diff_day > 30:
  144. return {
  145. "error": 1,
  146. "errmsg": "你的账号在超过30天未登录使用,账号已被锁定,请联系管理员处理,否则将被清除。",
  147. }
  148. redis_set_with_time(redis_login_key, str(0), 1)
  149. '''
  150. user_id = str(row.user_id)
  151. auth = {
  152. "user_id": user_id,
  153. "user_name": row.user_name,
  154. "nick_name": row.nick_name,
  155. "is_yzy_user": "0"
  156. }
  157. request.session['user_auth'] = auth
  158. request.session['user_auth_sign'] = data_auth_sign(auth)
  159. request.session['user_name'] = username
  160. # db_czrz_serv.log_username(db, row.uid, row.username, "登录", "后台管理账号+密码登录成功", request.client.host)
  161. row.login_date = datetime.now()
  162. row.login_ip = request.client.host
  163. # row.login = row.login + 1
  164. db.commit()
  165. access_token_expires = timedelta(days = 5)
  166. access_token = security.create_access_token(
  167. data={"sub": user_id}, expires_delta = access_token_expires
  168. )
  169. refresh_token_expires = timedelta(days = 5)
  170. refresh_token = security.create_access_token(
  171. data={"sub": user_id}, expires_delta = refresh_token_expires
  172. )
  173. return {
  174. "code": 200,
  175. "msg": "操作成功",
  176. "data": {
  177. "access_token": access_token,
  178. "refresh_token": refresh_token,
  179. "expire_in": 7200,
  180. "refresh_expire_in": 7200,
  181. "client_id": clientId,
  182. "scope": "",
  183. "openid": ""
  184. }
  185. }
  186. except Exception as e:
  187. traceback.print_exc()
  188. return {
  189. "code": 500,
  190. "msg": "帐号或者密码错误"
  191. }
  192. @router.post('/logout')
  193. async def logout(
  194. request: Request,
  195. db: Session = Depends(get_db),
  196. user: AuthUser = Depends(get_auth_user)
  197. ):
  198. logger.info("logout ok")
  199. request.session.clear()
  200. try:
  201. if user.is_yzy_user == 1:
  202. logout_url = settings.TYRZ_LOGOUT.format(settings.TYRZ_CLIENT_ID) + quote(settings.HOME_URL+"/yjzp/")
  203. logger.info(logout_url)
  204. else:
  205. logout_url = settings.HOME_URL + "/yjzp/"
  206. except:
  207. logout_url = settings.HOME_URL+"/yjzp/"
  208. return {
  209. "code": 200,
  210. "msg": "退出成功",
  211. "data": logout_url
  212. }
  213. # 小屏专用
  214. @router.post('/yzy/callback')
  215. async def yzy(
  216. request: Request,
  217. db: Session = Depends(get_db),
  218. data: dict = Depends(remove_xss_json)
  219. ):
  220. code = data['code']
  221. state = data['state']
  222. state_str = base64.b64decode(state).decode('utf-8')
  223. state_json = json.loads(state_str)
  224. logger.info("code:{}, {}", code, state_json)
  225. resp = YzyApi.get_user_info(code)
  226. if resp['errcode'] != 0:
  227. return {
  228. "code": 500,
  229. "msg": "Code异常"
  230. }
  231. user_id = resp['UserId']
  232. row = db.query(YzyOrgUserEntity).filter(YzyOrgUserEntity.userid == user_id).first()
  233. if row is None:
  234. return {
  235. "code": 500,
  236. "msg": "user_id异常"
  237. }
  238. yzy_account = row.account
  239. row = db.query(SysUser).filter(SysUser.yzy_account == yzy_account).first()
  240. if row is None:
  241. return {
  242. "code": 500,
  243. "msg": "用户不是本系统用户"
  244. }
  245. user_id = str(row.user_id)
  246. access_token_expires = timedelta(seconds = 7200)
  247. access_token = security.create_access_token(
  248. data={"sub": user_id}, expires_delta = access_token_expires
  249. )
  250. refresh_token_expires = timedelta(seconds = 7200)
  251. refresh_token = security.create_access_token(
  252. data={"sub": user_id}, expires_delta = refresh_token_expires
  253. )
  254. return {
  255. "code": 200,
  256. "msg": "粤政易登录成功",
  257. "data": {
  258. "access_token": access_token,
  259. "refresh_token": refresh_token,
  260. "expire_in": 7200,
  261. "refresh_expire_in": 7200,
  262. "scope": "",
  263. "redirect_url": state_json['redirect_url']
  264. }
  265. }
  266. # 粤政易token登录
  267. @router.post('/yzylogin')
  268. async def login(
  269. request: Request,
  270. data: dict = Depends(remove_xss_json),
  271. db: Session = Depends(get_db)
  272. ):
  273. code = data['code']
  274. redis_key = "yzy_" + code
  275. user_id = redis_get(redis_key)
  276. if user_id is None:
  277. return {
  278. "code": 500,
  279. "msg": "用户不是本系统用户"
  280. }
  281. row = db.query(SysUser).filter(SysUser.user_id == int(user_id)).first()
  282. if row is None:
  283. return {
  284. "code": 500,
  285. "msg": "用户不是本系统用户"
  286. }
  287. user_id = str(row.user_id)
  288. auth = {
  289. "user_id": user_id,
  290. "user_name": row.user_name,
  291. "nick_name": row.nick_name,
  292. "is_yzy_user": "1"
  293. }
  294. request.session['user_auth'] = auth
  295. request.session['user_auth_sign'] = data_auth_sign(auth)
  296. request.session['user_name'] = row.user_name
  297. # db_czrz_serv.log_username(db, row.uid, row.username, "登录", "后台管理账号+密码登录成功", request.client.host)
  298. row.login_date = datetime.now()
  299. row.login_ip = request.client.host
  300. # row.login = row.login + 1
  301. db.commit()
  302. access_token_expires = timedelta(days = 5)
  303. access_token = security.create_access_token(
  304. data={"sub": user_id}, expires_delta = access_token_expires
  305. )
  306. refresh_token_expires = timedelta(days = 5)
  307. refresh_token = security.create_access_token(
  308. data={"sub": user_id}, expires_delta = refresh_token_expires
  309. )
  310. return {
  311. "code": 200,
  312. "msg": "操作成功",
  313. "data": {
  314. "access_token": access_token,
  315. "refresh_token": refresh_token,
  316. "expire_in": 7200,
  317. "refresh_expire_in": 7200,
  318. "client_id": 0,
  319. "scope": "",
  320. "openid": ""
  321. }
  322. }