Autologin via `?hash=xxx` parameter in url
parent
2575cbfc11
commit
6bd01aaa45
|
@ -27,11 +27,25 @@ const validate = ({ username, password }) => {
|
||||||
return errors;
|
return errors;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function LoginForm() {
|
export default function LoginForm({ hash = null }) {
|
||||||
const post = usePost();
|
const post = usePost();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [message, setMessage] = useState();
|
const [message, setMessage] = useState();
|
||||||
|
|
||||||
|
const handleAutologin = async ({ hash }) => {
|
||||||
|
const autologin = await post('/api/auth/hash', {
|
||||||
|
hash,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (autologin.ok) {
|
||||||
|
return router.push('/');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (hash) {
|
||||||
|
handleAutologin({ hash });
|
||||||
|
}
|
||||||
|
|
||||||
const handleSubmit = async ({ username, password }) => {
|
const handleSubmit = async ({ username, password }) => {
|
||||||
const { ok, status, data } = await post('/api/auth/login', {
|
const { ok, status, data } = await post('/api/auth/login', {
|
||||||
username,
|
username,
|
||||||
|
|
|
@ -223,6 +223,16 @@ export async function getAccountById(user_id) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getAccountByHash(hash) {
|
||||||
|
return runQuery(
|
||||||
|
prisma.account.findUnique({
|
||||||
|
where: {
|
||||||
|
hash,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export async function getAccountByUsername(username) {
|
export async function getAccountByUsername(username) {
|
||||||
return runQuery(
|
return runQuery(
|
||||||
prisma.account.findUnique({
|
prisma.account.findUnique({
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { serialize } from 'cookie';
|
||||||
|
import { createSecureToken } from 'lib/crypto';
|
||||||
|
import { getAccountByHash } from 'lib/queries';
|
||||||
|
import { AUTH_COOKIE_NAME } from 'lib/constants';
|
||||||
|
import { ok, unauthorized, badRequest } from 'lib/response';
|
||||||
|
|
||||||
|
export default async (req, res) => {
|
||||||
|
const { hash } = req.body;
|
||||||
|
|
||||||
|
if (!hash) {
|
||||||
|
return badRequest(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
const account = await getAccountByHash(hash);
|
||||||
|
|
||||||
|
if (account) {
|
||||||
|
const { user_id, username, is_admin } = account;
|
||||||
|
const token = await createSecureToken({ user_id, username, is_admin });
|
||||||
|
const cookie = serialize(AUTH_COOKIE_NAME, token, {
|
||||||
|
path: '/',
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: true,
|
||||||
|
maxAge: 60 * 60 * 24 * 365,
|
||||||
|
});
|
||||||
|
|
||||||
|
res.setHeader('Set-Cookie', [cookie]);
|
||||||
|
|
||||||
|
return ok(res, { token });
|
||||||
|
}
|
||||||
|
|
||||||
|
return unauthorized(res);
|
||||||
|
};
|
|
@ -15,7 +15,7 @@ export default function DashboardPage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout header={false} footer={false}>
|
||||||
<WebsiteList userId={userId} />
|
<WebsiteList userId={userId} />
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Layout from 'components/layout/Layout';
|
import Layout from 'components/layout/Layout';
|
||||||
import LoginForm from 'components/forms/LoginForm';
|
import LoginForm from 'components/forms/LoginForm';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
|
||||||
export default function LoginPage() {
|
export default function LoginPage() {
|
||||||
|
const { query } = useRouter();
|
||||||
return (
|
return (
|
||||||
<Layout title="login" header={false} footer={false} center>
|
<Layout title="login" header={false} footer={false} center>
|
||||||
<LoginForm />
|
<LoginForm hash={query.hash} />
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ export default function DetailsPage() {
|
||||||
const [websiteId] = id;
|
const [websiteId] = id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout header={false} footer={false}>
|
||||||
<WebsiteDetails websiteId={websiteId} />
|
<WebsiteDetails websiteId={websiteId} />
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,6 +11,7 @@ model account {
|
||||||
user_id Int @id @default(autoincrement()) @db.UnsignedInt
|
user_id Int @id @default(autoincrement()) @db.UnsignedInt
|
||||||
username String @unique @db.VarChar(255)
|
username String @unique @db.VarChar(255)
|
||||||
password String @db.VarChar(60)
|
password String @db.VarChar(60)
|
||||||
|
hash String @unique @db.VarChar(512)
|
||||||
is_admin Boolean @default(false)
|
is_admin Boolean @default(false)
|
||||||
created_at DateTime? @default(now()) @db.Timestamp(0)
|
created_at DateTime? @default(now()) @db.Timestamp(0)
|
||||||
updated_at DateTime? @default(now()) @db.Timestamp(0)
|
updated_at DateTime? @default(now()) @db.Timestamp(0)
|
||||||
|
|
|
@ -11,6 +11,7 @@ model account {
|
||||||
user_id Int @id @default(autoincrement())
|
user_id Int @id @default(autoincrement())
|
||||||
username String @unique @db.VarChar(255)
|
username String @unique @db.VarChar(255)
|
||||||
password String @db.VarChar(60)
|
password String @db.VarChar(60)
|
||||||
|
hash String @unique @db.VarChar(512)
|
||||||
is_admin Boolean @default(false)
|
is_admin Boolean @default(false)
|
||||||
created_at DateTime? @default(now()) @db.Timestamptz(6)
|
created_at DateTime? @default(now()) @db.Timestamptz(6)
|
||||||
updated_at DateTime? @default(now()) @db.Timestamptz(6)
|
updated_at DateTime? @default(now()) @db.Timestamptz(6)
|
||||||
|
|
Loading…
Reference in New Issue