Next.jsとSupabaseを用いたログイン機能の作成
解決したいこと
Next.jsとsupabaseのデータベースの接続
例)
Next.jsでsupabaseのPostgreSQLを用いて生徒側のログインと管理者側のログイン機能を作成しようとしていますが、データベースに登録されている値と全く同じにもかかわらず認証できません。
発生している問題・エラー
GET /api/auth/providers 200 in 30ms
GET /api/auth/csrf 200 in 17ms
POST /api/auth/callback/credentials 401 in 161ms
該当するソースコード
LoginModal.tsx
'use client';
import React, { useState } from "react";
import { Button, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Input, Checkbox, Link, Spacer } from '@nextui-org/react';
import { useRouter } from 'next/navigation';
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm, SubmitHandler } from "react-hook-form";
import { InputsType, inputs } from "@/schema/LoginSchema";
import { signIn } from 'next-auth/react';
interface StudentModalProps {
showFlag: boolean;
ChangeFlag: () => void;
}
export const StudentLoginModal: React.FC<StudentModalProps> = (props) => {
const [studentId, setStudentId] = useState('');
const [password, setPassword] = useState('');
const router = useRouter();
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm<InputsType>({
resolver: zodResolver(inputs)
});
const onChangeModal = () => {
props.ChangeFlag();
reset();
setStudentId('');
setPassword('');
};
const onSubmit: SubmitHandler<InputsType> = async (data) => {
try {
const result = await signIn("credentials", {
redirect: false,
student_id: data.student_id,
password: data.password,
});
if (result?.ok) {
router.push('/dashboard');
} else {
alert('ログインに失敗しました。IDまたはパスワードを確認してください。');
}
} catch (error) {
console.error('認証中にエラーが発生しました:', error);
alert('エラーが発生しました。再度お試しください。');
}
};
return (
<>
<Modal backdrop="blur" isOpen={props.showFlag} onOpenChange={onChangeModal}>
<ModalContent>
{(onClose) => (
<form onSubmit={handleSubmit(onSubmit)}>
<ModalHeader className="flex flex-col gap-1">ログイン情報を入力</ModalHeader>
<ModalBody className="items-center justify-center">
<Input
{...register("student_id")}
autoFocus
label="Student ID"
placeholder="Enter your student ID"
variant="bordered"
value={studentId}
onChange={(e) => setStudentId(e.target.value)}
/>
{errors.student_id && <p className="text-red-500 text-xs mt-1">{errors.student_id.message}</p>}
<Input
{...register("password")}
label="Password"
placeholder="Enter your password"
type="password"
variant="bordered"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
{errors.password && <p className="text-red-500 text-xs mt-1">{errors.password.message}</p>}
<div className="flex py-2 px-1 justify-between">
<Checkbox
classNames={{
label: "text-small",
}}
>
ログインを記憶する
</Checkbox>
<Spacer className="px-14" />
<Link color="primary" href="#" size="sm">
Forgot password?
</Link>
</div>
</ModalBody>
<ModalFooter>
<Button color="danger" variant="light" onPress={onClose}>
キャンセル
</Button>
<Button color="primary" type="submit" onClick={handleSubmit(onSubmit)}>
ログイン
</Button>
</ModalFooter>
</form>
)}
</ModalContent>
</Modal>
</>
);
};
AuthOption.tsx
import CredentialsProvider from 'next-auth/providers/credentials';
import { NextAuthOptions } from 'next-auth';
import { supabase } from '@/lib/supabaseClient';
import bcrypt from 'bcrypt';
export const authOptions: NextAuthOptions = {
providers: [
CredentialsProvider({
name: 'Credential',
credentials: {
student_id: { label: 'student_id', type: 'text' },
password: { label: 'password', type: 'text' },
},
async authorize(credentials) {
if (!credentials) throw new Error('No credentials provided');
const { data, error } = await supabase
.from('Student')
.select('student_id, password')
.eq('student_id', credentials.student_id)
.single();
if (!data) {
console.error('User not found:', error);
return null;
}
else if(error){
console.error('Supabase error:', error);
return null;
}
alert(data.password)
//const isPasswordValid = await bcrypt.compare(credentials.password, data.password);
if (credentials.password == data.password) {
console.error('Invalid password');
return null;
}
return { id: data.student_id };
},
}),
],
session: { strategy: 'jwt' },
callbacks: {
async jwt({ token, user }) {
if (user) token.id = user.id;
return token;
},
async session({ session, token }) {
session.user = { ...session.user, id: token.id as string };
return session;
},
},
pages: { signIn: '/login' },
debug: true,
};
※bcryptはデータベースと参照のため無効にしてあります。
route.ts
import NextAuth from 'next-auth';
import { authOptions } from '@/lib/authOptions';
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
ダイレクト接続も試みましたがダメでした。
0