feat: add github auth integrate
This commit is contained in:
parent
03bc9b5125
commit
7f7c95b11c
@ -4,6 +4,7 @@ import { useUserStore } from '@/store/user';
|
|||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { trpc } from '../trpc';
|
import { trpc } from '../trpc';
|
||||||
import { useTranslation } from '@i18next-toolkit/react';
|
import { useTranslation } from '@i18next-toolkit/react';
|
||||||
|
import { BuiltInProviderType } from '@auth/core/providers';
|
||||||
|
|
||||||
export function useAuth() {
|
export function useAuth() {
|
||||||
const trpcUtils = trpc.useUtils();
|
const trpcUtils = trpc.useUtils();
|
||||||
@ -38,6 +39,32 @@ export function useAuth() {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const loginWithOAuth = useEvent(async (provider: BuiltInProviderType) => {
|
||||||
|
let res: SignInResponse | undefined;
|
||||||
|
try {
|
||||||
|
res = await signIn(provider, {
|
||||||
|
redirect: false,
|
||||||
|
});
|
||||||
|
console.log('res', res);
|
||||||
|
} catch (err) {
|
||||||
|
toast.error(t('Login failed'));
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res?.error) {
|
||||||
|
toast.error(t('Login failed'));
|
||||||
|
throw new Error('Login failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
const userInfo = await trpcUtils.user.info.fetch();
|
||||||
|
if (!userInfo) {
|
||||||
|
toast.error(t('Can not get current user info'));
|
||||||
|
throw new Error('Login failed, ');
|
||||||
|
}
|
||||||
|
|
||||||
|
return userInfo;
|
||||||
|
});
|
||||||
|
|
||||||
const logout = useEvent(async () => {
|
const logout = useEvent(async () => {
|
||||||
await signOut({
|
await signOut({
|
||||||
redirect: false,
|
redirect: false,
|
||||||
@ -49,6 +76,7 @@ export function useAuth() {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
loginWithPassword,
|
loginWithPassword,
|
||||||
|
loginWithOAuth,
|
||||||
logout,
|
logout,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ const defaultGlobalConfig: AppRouterOutput['global']['config'] = {
|
|||||||
allowRegister: false,
|
allowRegister: false,
|
||||||
alphaMode: false,
|
alphaMode: false,
|
||||||
disableAnonymousTelemetry: false,
|
disableAnonymousTelemetry: false,
|
||||||
|
authProvider: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const callAnonymousTelemetry = once(() => {
|
const callAnonymousTelemetry = once(() => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { createFileRoute, redirect, useNavigate } from '@tanstack/react-router';
|
import { createFileRoute, redirect, useNavigate } from '@tanstack/react-router';
|
||||||
import { useGlobalConfig } from '@/hooks/useConfig';
|
import { useGlobalConfig } from '@/hooks/useConfig';
|
||||||
import { Form, Typography } from 'antd';
|
import { Divider, Form, Typography } from 'antd';
|
||||||
import { useTranslation } from '@i18next-toolkit/react';
|
import { useTranslation } from '@i18next-toolkit/react';
|
||||||
import { setUserInfo } from '@/store/user';
|
import { setUserInfo } from '@/store/user';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
@ -8,6 +8,7 @@ import { Button } from '@/components/ui/button';
|
|||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { useAuth } from '@/api/authjs/useAuth';
|
import { useAuth } from '@/api/authjs/useAuth';
|
||||||
import { useEventWithLoading } from '@/hooks/useEvent';
|
import { useEventWithLoading } from '@/hooks/useEvent';
|
||||||
|
import { LuGithub } from 'react-icons/lu';
|
||||||
|
|
||||||
export const Route = createFileRoute('/login')({
|
export const Route = createFileRoute('/login')({
|
||||||
validateSearch: z.object({
|
validateSearch: z.object({
|
||||||
@ -29,7 +30,7 @@ function LoginComponent() {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const search = Route.useSearch();
|
const search = Route.useSearch();
|
||||||
|
|
||||||
const { loginWithPassword } = useAuth();
|
const { loginWithPassword, loginWithOAuth } = useAuth();
|
||||||
|
|
||||||
const [handleLogin, loading] = useEventWithLoading(async (values: any) => {
|
const [handleLogin, loading] = useEventWithLoading(async (values: any) => {
|
||||||
const userInfo = await loginWithPassword(values.username, values.password);
|
const userInfo = await loginWithPassword(values.username, values.password);
|
||||||
@ -41,7 +42,7 @@ function LoginComponent() {
|
|||||||
replace: true,
|
replace: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const { allowRegister } = useGlobalConfig();
|
const { allowRegister, authProvider } = useGlobalConfig();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full w-full items-center justify-center dark:bg-gray-900">
|
<div className="flex h-full w-full items-center justify-center dark:bg-gray-900">
|
||||||
@ -96,6 +97,22 @@ function LoginComponent() {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
|
{authProvider.length > 0 && (
|
||||||
|
<>
|
||||||
|
<Divider>{t('Or')}</Divider>
|
||||||
|
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
className="h-12 w-12 p-3"
|
||||||
|
onClick={() => loginWithOAuth('github')}
|
||||||
|
>
|
||||||
|
<LuGithub size={24} />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Auth, AuthConfig, createActionURL } from '@auth/core';
|
import { Auth, AuthConfig, createActionURL } from '@auth/core';
|
||||||
import Nodemailer from '@auth/core/providers/nodemailer';
|
import Nodemailer from '@auth/core/providers/nodemailer';
|
||||||
import Credentials from '@auth/core/providers/credentials';
|
import Credentials from '@auth/core/providers/credentials';
|
||||||
|
import Github from '@auth/core/providers/github';
|
||||||
import { env } from '../utils/env.js';
|
import { env } from '../utils/env.js';
|
||||||
import { prisma } from './_client.js';
|
import { prisma } from './_client.js';
|
||||||
import type { PrismaClient, Prisma, User } from '@prisma/client';
|
import type { PrismaClient, Prisma, User } from '@prisma/client';
|
||||||
@ -28,7 +29,8 @@ export interface UserAuthPayload {
|
|||||||
export const authConfig: Omit<AuthConfig, 'raw'> = {
|
export const authConfig: Omit<AuthConfig, 'raw'> = {
|
||||||
debug: env.isProd ? false : true,
|
debug: env.isProd ? false : true,
|
||||||
basePath: '/api/auth',
|
basePath: '/api/auth',
|
||||||
providers: [
|
trustHost: true,
|
||||||
|
providers: _.compact([
|
||||||
Credentials({
|
Credentials({
|
||||||
id: 'account',
|
id: 'account',
|
||||||
name: 'Account',
|
name: 'Account',
|
||||||
@ -52,6 +54,7 @@ export const authConfig: Omit<AuthConfig, 'raw'> = {
|
|||||||
return toAdapterUser(user);
|
return toAdapterUser(user);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
env.auth.provider.includes('email') &&
|
||||||
Nodemailer({
|
Nodemailer({
|
||||||
id: 'email',
|
id: 'email',
|
||||||
name: 'Email',
|
name: 'Email',
|
||||||
@ -73,7 +76,19 @@ export const authConfig: Omit<AuthConfig, 'raw'> = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
env.auth.provider.includes('github') &&
|
||||||
|
Github({
|
||||||
|
id: 'github',
|
||||||
|
name: 'Github',
|
||||||
|
...env.auth.github,
|
||||||
|
}),
|
||||||
|
env.auth.provider.includes('google') &&
|
||||||
|
Github({
|
||||||
|
id: 'google',
|
||||||
|
name: 'Google',
|
||||||
|
...env.auth.google,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
adapter: TianjiPrismaAdapter(prisma),
|
adapter: TianjiPrismaAdapter(prisma),
|
||||||
secret: env.auth.secret,
|
secret: env.auth.secret,
|
||||||
session: {
|
session: {
|
||||||
|
@ -23,6 +23,7 @@ export const globalRouter = router({
|
|||||||
alphaMode: z.boolean(),
|
alphaMode: z.boolean(),
|
||||||
disableAnonymousTelemetry: z.boolean(),
|
disableAnonymousTelemetry: z.boolean(),
|
||||||
customTrackerScriptName: z.string().optional(),
|
customTrackerScriptName: z.string().optional(),
|
||||||
|
authProvider: z.array(z.string()),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.query(async ({ input }) => {
|
.query(async ({ input }) => {
|
||||||
@ -34,6 +35,7 @@ export const globalRouter = router({
|
|||||||
alphaMode: env.alphaMode,
|
alphaMode: env.alphaMode,
|
||||||
disableAnonymousTelemetry: env.disableAnonymousTelemetry,
|
disableAnonymousTelemetry: env.disableAnonymousTelemetry,
|
||||||
customTrackerScriptName: env.customTrackerScriptName,
|
customTrackerScriptName: env.customTrackerScriptName,
|
||||||
|
authProvider: env.auth.provider,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { v1 as uuid } from 'uuid';
|
import { v1 as uuid } from 'uuid';
|
||||||
import md5 from 'md5';
|
import md5 from 'md5';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
const jwtSecret =
|
const jwtSecret =
|
||||||
!process.env.JWT_SECRET ||
|
!process.env.JWT_SECRET ||
|
||||||
@ -13,11 +14,24 @@ export const env = {
|
|||||||
jwtSecret,
|
jwtSecret,
|
||||||
port: Number(process.env.PORT || 12345),
|
port: Number(process.env.PORT || 12345),
|
||||||
auth: {
|
auth: {
|
||||||
|
provider: _.compact([
|
||||||
|
!!process.env.EMAIL_SERVER && 'email',
|
||||||
|
!!process.env.AUTH_GITHUB_ID && 'github',
|
||||||
|
!!process.env.AUTH_GOOGLE_ID && 'google',
|
||||||
|
]),
|
||||||
secret: process.env.AUTH_SECRET || md5(jwtSecret),
|
secret: process.env.AUTH_SECRET || md5(jwtSecret),
|
||||||
email: {
|
email: {
|
||||||
server: process.env.EMAIL_SERVER,
|
server: process.env.EMAIL_SERVER,
|
||||||
from: process.env.EMAIL_FROM,
|
from: process.env.EMAIL_FROM,
|
||||||
},
|
},
|
||||||
|
github: {
|
||||||
|
clientId: process.env.AUTH_GITHUB_ID,
|
||||||
|
clientSecret: process.env.AUTH_GITHUB_SECRET,
|
||||||
|
},
|
||||||
|
google: {
|
||||||
|
clientId: process.env.AUTH_GOOGLE_ID,
|
||||||
|
clientSecret: process.env.AUTH_GOOGLE_SECRET,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
allowRegister: checkEnvTrusty(process.env.ALLOW_REGISTER),
|
allowRegister: checkEnvTrusty(process.env.ALLOW_REGISTER),
|
||||||
allowOpenapi: checkEnvTrusty(process.env.ALLOW_OPENAPI ?? 'true'),
|
allowOpenapi: checkEnvTrusty(process.env.ALLOW_OPENAPI ?? 'true'),
|
||||||
|
Loading…
Reference in New Issue
Block a user