update oauth2 (#84)

* update oauth2

* i18n

* fix validation

* chore: auto-fix linting and formatting issues

---------

Co-authored-by: uubulb <uubulb@users.noreply.github.com>
This commit is contained in:
UUBulb
2024-12-31 23:11:41 +08:00
committed by GitHub
parent d54372fb0c
commit 5517a8df38
8 changed files with 418 additions and 435 deletions

View File

@@ -16,35 +16,9 @@ export const getOauth2RedirectURL = async (
}) })
} }
export const bindOauth2 = async (
provider: string,
state: string,
code: string,
): Promise<ModelOauth2LoginResponse> => {
return fetcher<ModelOauth2LoginResponse>(
FetcherMethod.POST,
`/api/v1/oauth2/${provider}/bind`,
{
state: state,
code: code,
},
)
}
export const unbindOauth2 = async (provider: string): Promise<ModelOauth2LoginResponse> => { export const unbindOauth2 = async (provider: string): Promise<ModelOauth2LoginResponse> => {
return fetcher<ModelOauth2LoginResponse>( return fetcher<ModelOauth2LoginResponse>(
FetcherMethod.POST, FetcherMethod.POST,
`/api/v1/oauth2/${provider}/unbind`, `/api/v1/oauth2/${provider}/unbind`,
) )
} }
export const oauth2callback = async (
provider: string,
state: string,
code: string,
): Promise<void> => {
return fetcher<void>(FetcherMethod.POST, `/api/v1/oauth2/${provider}/callback`, {
state,
code,
})
}

View File

@@ -1,5 +1,6 @@
import { getProfile, updateProfile } from "@/api/user" import { getProfile, updateProfile } from "@/api/user"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox"
import { import {
Dialog, Dialog,
DialogClose, DialogClose,
@@ -19,8 +20,10 @@ import {
FormMessage, FormMessage,
} from "@/components/ui/form" } from "@/components/ui/form"
import { Input } from "@/components/ui/input" import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { ScrollArea } from "@/components/ui/scroll-area" import { ScrollArea } from "@/components/ui/scroll-area"
import { useMainStore } from "@/hooks/useMainStore" import { useMainStore } from "@/hooks/useMainStore"
import { asOptionalField } from "@/lib/utils"
import { zodResolver } from "@hookform/resolvers/zod" import { zodResolver } from "@hookform/resolvers/zod"
import { useState } from "react" import { useState } from "react"
import { useForm } from "react-hook-form" import { useForm } from "react-hook-form"
@@ -32,6 +35,7 @@ const profileFormSchema = z.object({
original_password: z.string().min(5).max(72), original_password: z.string().min(5).max(72),
new_password: z.string().min(8).max(72), new_password: z.string().min(8).max(72),
new_username: z.string().min(1).max(32), new_username: z.string().min(1).max(32),
reject_password: asOptionalField(z.boolean()),
}) })
export const ProfileCard = ({ className }: { className: string }) => { export const ProfileCard = ({ className }: { className: string }) => {
@@ -44,6 +48,7 @@ export const ProfileCard = ({ className }: { className: string }) => {
original_password: "", original_password: "",
new_password: "", new_password: "",
new_username: profile?.username, new_username: profile?.username,
reject_password: profile?.reject_password,
}, },
resetOptions: { resetOptions: {
keepDefaultValues: false, keepDefaultValues: false,
@@ -122,6 +127,26 @@ export const ProfileCard = ({ className }: { className: string }) => {
</FormItem> </FormItem>
)} )}
/> />
<FormField
control={form.control}
name="reject_password"
render={({ field }) => (
<FormItem className="flex items-center space-x-2">
<FormControl>
<div className="flex items-center gap-2">
<Checkbox
checked={field.value}
onCheckedChange={field.onChange}
/>
<Label className="text-sm">
{t("RejectPassword")}
</Label>
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<DialogFooter className="justify-end"> <DialogFooter className="justify-end">
<DialogClose asChild> <DialogClose asChild>

View File

@@ -1,4 +1,3 @@
import { oauth2callback } from "@/api/oauth2"
import { getProfile, login as loginRequest } from "@/api/user" import { getProfile, login as loginRequest } from "@/api/user"
import { AuthContextProps } from "@/types" import { AuthContextProps } from "@/types"
import { createContext, useContext, useEffect, useMemo } from "react" import { createContext, useContext, useEffect, useMemo } from "react"
@@ -45,9 +44,8 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
} }
} }
const loginOauth2 = async (provider: string, state: string, code: string) => { const loginOauth2 = async () => {
try { try {
await oauth2callback(provider, state, code)
const user = await getProfile() const user = await getProfile()
user.role = user.role || 0 user.role = user.role || 0
setProfile(user) setProfile(user)

View File

@@ -174,5 +174,6 @@
"ConnectedAt": "Connected at", "ConnectedAt": "Connected at",
"OnlineUser": "Online User", "OnlineUser": "Online User",
"Total": "Total", "Total": "Total",
"ConfirmBlock": "Confirm Block" "ConfirmBlock": "Confirm Block",
"RejectPassword": "Reject Password Login"
} }

View File

@@ -35,11 +35,9 @@ function Login() {
const { data: settingData } = useSetting() const { data: settingData } = useSetting()
useEffect(() => { useEffect(() => {
const oauth2Code = new URLSearchParams(window.location.search).get("code") const oauth2 = new URLSearchParams(window.location.search).get("oauth2")
const oauth2State = new URLSearchParams(window.location.search).get("state") if (oauth2) {
const oauth2Provider = new URLSearchParams(window.location.search).get("provider") loginOauth2()
if (oauth2Code && oauth2State && oauth2Provider) {
loginOauth2(oauth2Provider, oauth2State, oauth2Code)
} }
}, [window.location.search]) }, [window.location.search])

View File

@@ -1,4 +1,4 @@
import { Oauth2RequestType, bindOauth2, getOauth2RedirectURL, unbindOauth2 } from "@/api/oauth2" import { Oauth2RequestType, getOauth2RedirectURL, unbindOauth2 } from "@/api/oauth2"
import { getProfile } from "@/api/user" import { getProfile } from "@/api/user"
import { ProfileCard } from "@/components/profile" import { ProfileCard } from "@/components/profile"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
@@ -19,22 +19,12 @@ export default function ProfilePage() {
const isDesktop = useMediaQuery("(min-width: 890px)") const isDesktop = useMediaQuery("(min-width: 890px)")
useEffect(() => { useEffect(() => {
const oauth2Code = new URLSearchParams(window.location.search).get("code") const oauth2 = new URLSearchParams(window.location.search).get("oauth2")
const oauth2State = new URLSearchParams(window.location.search).get("state") if (oauth2) {
const oauth2Provider = new URLSearchParams(window.location.search).get("provider")
if (oauth2Code && oauth2State && oauth2Provider) {
bindOauth2(oauth2Provider, oauth2State, oauth2Code)
.catch((error) => {
toast.error(error.message)
})
.then(() => {
getProfile().then((profile) => { getProfile().then((profile) => {
setProfile(profile) setProfile(profile)
}) })
})
.finally(() => {
window.history.replaceState({}, document.title, window.location.pathname) window.history.replaceState({}, document.title, window.location.pathname)
})
} }
}, [window.location.search]) }, [window.location.search])
@@ -50,9 +40,8 @@ export default function ProfilePage() {
const unbindO2 = async (provider: string) => { const unbindO2 = async (provider: string) => {
try { try {
await unbindOauth2(provider) await unbindOauth2(provider)
getProfile().then((profile) => { const profile = await getProfile()
setProfile(profile) setProfile(profile)
})
} catch (error: any) { } catch (error: any) {
toast.error(error.message) toast.error(error.message)
} }

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,6 @@ import { ModelProfile } from "@/types"
export interface AuthContextProps { export interface AuthContextProps {
profile: ModelProfile | undefined profile: ModelProfile | undefined
login: (username: string, password: string) => void login: (username: string, password: string) => void
loginOauth2: (provider: string, state: string, code: string) => void loginOauth2: () => void
logout: () => void logout: () => void
} }