GetLoginUrl.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. const API = require("../../../lib/API")
  2. const axios = require('axios')
  3. const { BaseStdResponse } = require("../../../BaseStdResponse");
  4. const https = require("https")
  5. const { getUniLoginRuntimeConfig, normalizeSocialType } = require('../../../lib/UniLoginClient')
  6. class GetLoginUrl extends API {
  7. constructor() {
  8. super();
  9. this.setPath('/UniLogin/GetLoginUrl')
  10. this.setMethod('GET')
  11. }
  12. async onRequest(req, res) {
  13. let { type, device, action, from, mode } = req.query
  14. type = normalizeSocialType(type)
  15. if (!type)
  16. return res.json({
  17. ...BaseStdResponse.ERR,
  18. msg: '不支持的第三方登录类型'
  19. })
  20. let uniConfig
  21. try {
  22. uniConfig = await getUniLoginRuntimeConfig({ requireEnabledType: type })
  23. } catch (error) {
  24. return res.json({
  25. ...BaseStdResponse.ERR,
  26. msg: error.message || '聚合登录暂未配置,请使用账号密码登录'
  27. })
  28. }
  29. /** 解析 URL 与 hash 内查询串,判断 query 是否已包含某键(避免对整段 URL 做子串误判) */
  30. const redirectUrlHasQueryKey = (redirectUrl, key) => {
  31. if (!redirectUrl || !key) return false
  32. try {
  33. const u = new URL(redirectUrl)
  34. if (u.searchParams.has(key)) return true
  35. const h = u.hash || ''
  36. const qPos = h.indexOf('?')
  37. if (qPos === -1) return false
  38. return new URLSearchParams(h.slice(qPos + 1)).has(key)
  39. } catch {
  40. return false
  41. }
  42. }
  43. const appendQuery = (redirectUrl) => {
  44. const params = []
  45. if (mode && !redirectUrlHasQueryKey(redirectUrl, 'mode'))
  46. params.push(`mode=${encodeURIComponent(mode)}`)
  47. if (action && !redirectUrlHasQueryKey(redirectUrl, 'action'))
  48. params.push(`action=${encodeURIComponent(action)}`)
  49. if (from && !redirectUrlHasQueryKey(redirectUrl, 'from'))
  50. params.push(`from=${encodeURIComponent(from)}`)
  51. if (params.length === 0)
  52. return redirectUrl
  53. return `${redirectUrl}${redirectUrl.includes('?') ? '&' : '?'}${params.join('&')}`
  54. }
  55. let redirectUri = appendQuery(uniConfig.return_url)
  56. let url = `${uniConfig.url}/connect.php?act=login&appid=${uniConfig.appid}&appkey=${uniConfig.appkey}&type=${type}&redirect_uri=${encodeURIComponent(redirectUri)}`
  57. if (device && device === 'uniapp')
  58. url = `${uniConfig.url}/connect.php?act=login&appid=${uniConfig.appid}&appkey=${uniConfig.appkey}&type=${type}&redirect_uri=${encodeURIComponent(appendQuery(uniConfig.uni_return_url))}`
  59. try {
  60. const r = await axios.get(url, {
  61. proxy: false,
  62. httpsAgent: new https.Agent({
  63. rejectUnauthorized: false
  64. })
  65. })
  66. if (!r || r.data?.code !== 0 || !r.data?.url) {
  67. this.logger.error(`获取聚合登录链接失败!${r.data?.msg || 'api接口错误'}`)
  68. return res.json({
  69. ...BaseStdResponse.ERR,
  70. msg: '请尝试其他登录方式或稍后再试'
  71. })
  72. }
  73. res.json({
  74. ...BaseStdResponse.OK,
  75. data: r.data.url
  76. })
  77. } catch (error) {
  78. this.logger.error(`获取聚合登录链接失败!${error.message || 'api接口错误'}`)
  79. return res.json({
  80. ...BaseStdResponse.ERR,
  81. msg: '请尝试其他登录方式或稍后再试!'
  82. })
  83. }
  84. }
  85. }
  86. module.exports.GetLoginUrl = GetLoginUrl;