page.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. 'use client'
  2. import cn from 'classnames'
  3. import { useRouter, useSearchParams } from 'next/navigation'
  4. import type { FC } from 'react'
  5. import React, { useEffect, useState } from 'react'
  6. import { useTranslation } from 'react-i18next'
  7. import Toast from '@/app/components/base/toast'
  8. import Button from '@/app/components/base/button'
  9. import { fetchSystemFeatures, fetchWebOAuth2SSOUrl, fetchWebOIDCSSOUrl, fetchWebSAMLSSOUrl } from '@/service/share'
  10. import LogoSite from '@/app/components/base/logo/logo-site'
  11. import { setAccessToken } from '@/app/components/share/utils'
  12. const WebSSOForm: FC = () => {
  13. const searchParams = useSearchParams()
  14. const redirectUrl = searchParams.get('redirect_url')
  15. const tokenFromUrl = searchParams.get('web_sso_token')
  16. const message = searchParams.get('message')
  17. const router = useRouter()
  18. const { t } = useTranslation()
  19. const [isLoading, setIsLoading] = useState(false)
  20. const [protocal, setProtocal] = useState('')
  21. useEffect(() => {
  22. const fetchFeaturesAndSetToken = async () => {
  23. await fetchSystemFeatures().then((res) => {
  24. setProtocal(res.sso_enforced_for_web_protocol)
  25. })
  26. // Callback from SSO, process token and redirect
  27. if (tokenFromUrl && redirectUrl) {
  28. const appCode = redirectUrl.split('/').pop()
  29. if (!appCode) {
  30. Toast.notify({
  31. type: 'error',
  32. message: 'redirect url is invalid. App code is not found.',
  33. })
  34. return
  35. }
  36. await setAccessToken(appCode, tokenFromUrl)
  37. router.push(redirectUrl)
  38. }
  39. }
  40. fetchFeaturesAndSetToken()
  41. if (message) {
  42. Toast.notify({
  43. type: 'error',
  44. message,
  45. })
  46. }
  47. }, [])
  48. const handleSSOLogin = () => {
  49. setIsLoading(true)
  50. if (!redirectUrl) {
  51. Toast.notify({
  52. type: 'error',
  53. message: 'redirect url is not found.',
  54. })
  55. setIsLoading(false)
  56. return
  57. }
  58. const appCode = redirectUrl.split('/').pop()
  59. if (!appCode) {
  60. Toast.notify({
  61. type: 'error',
  62. message: 'redirect url is invalid. App code is not found.',
  63. })
  64. return
  65. }
  66. if (protocal === 'saml') {
  67. fetchWebSAMLSSOUrl(appCode, redirectUrl).then((res) => {
  68. router.push(res.url)
  69. }).finally(() => {
  70. setIsLoading(false)
  71. })
  72. }
  73. else if (protocal === 'oidc') {
  74. fetchWebOIDCSSOUrl(appCode, redirectUrl).then((res) => {
  75. router.push(res.url)
  76. }).finally(() => {
  77. setIsLoading(false)
  78. })
  79. }
  80. else if (protocal === 'oauth2') {
  81. fetchWebOAuth2SSOUrl(appCode, redirectUrl).then((res) => {
  82. router.push(res.url)
  83. }).finally(() => {
  84. setIsLoading(false)
  85. })
  86. }
  87. else {
  88. Toast.notify({
  89. type: 'error',
  90. message: 'sso protocal is not supported.',
  91. })
  92. setIsLoading(false)
  93. }
  94. }
  95. return (
  96. <div className={cn(
  97. 'flex w-full min-h-screen',
  98. 'sm:p-4 lg:p-8',
  99. 'gap-x-20',
  100. 'justify-center lg:justify-start',
  101. )}>
  102. <div className={
  103. cn(
  104. 'flex w-full flex-col bg-white shadow rounded-2xl shrink-0',
  105. 'space-between',
  106. )
  107. }>
  108. <div className='flex items-center justify-between p-6 w-full'>
  109. <LogoSite />
  110. </div>
  111. <div className={
  112. cn(
  113. 'flex flex-col items-center w-full grow items-center justify-center',
  114. 'px-6',
  115. 'md:px-[108px]',
  116. )
  117. }>
  118. <div className='flex flex-col md:w-[400px]'>
  119. <div className="w-full mx-auto">
  120. <h2 className="text-[32px] font-bold text-gray-900">{t('login.pageTitle')}</h2>
  121. </div>
  122. <div className="w-full mx-auto mt-10">
  123. <Button
  124. tabIndex={0}
  125. type='primary'
  126. onClick={() => { handleSSOLogin() }}
  127. disabled={isLoading}
  128. className="w-full !fone-medium !text-sm"
  129. >{t('login.sso')}
  130. </Button>
  131. </div>
  132. </div>
  133. </div>
  134. </div>
  135. </div>
  136. )
  137. }
  138. export default React.memo(WebSSOForm)