Skip to content

Commit

Permalink
demo page redirection, with getServerSideProps
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-burel committed Jun 24, 2020
1 parent e8db97e commit 564840d
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 33 deletions.
16 changes: 16 additions & 0 deletions cypress/integration/vns/private.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,20 @@ describe("private pages", () => {
cy.get("h1").contains("private").should("exist");
});
});
describe("shallow", () => {
it("redirects back to public page when accessing private page", () => {
cy.visit("/vns/debug/public");
cy.get(".private-shallow").click();
cy.url().should("not.match", /private/);
cy.url().should("match", /public/);
cy.get("h1").contains("public").should("exist");
});
it("do not redirect when accessing allowed private page", () => {
cy.visit("/vns/debug/public");
cy.get(".private-allowed-shallow").click();
cy.url().should("not.match", /public/);
cy.url().should("match", /private/);
cy.get("h1").contains("private").should("exist");
});
});
});
70 changes: 70 additions & 0 deletions src/pages/vns/debug/private-initial-props.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* Demo an authenticated page
* @see https://spectrum.chat/next-js/general/redirect-the-right-way~6d1b6631-340d-4de3-9127-8cf08ec02bcc
* @see https://jasonraimondi.com/posts/secure-a-next-js-application-with-jwt-and-a-private-route-higher-order-component/#add-a-_privateroute_-higher-order-component-hoc-to-secure-the-app-from-unauthorized-access
*/
import Link from "next/link";
import { NextPage, NextPageContext } from "next";
import Router from "next/router";
import debug from "debug";
const debugNext = debug("vns:next");

// @ssr-only
export const redirectServer = (ctx: NextPageContext) => (pathname: string) => {
ctx.res.writeHead(302, { Location: pathname });
ctx.res.end();
};

const isServerSideRenderCtx = (ctx?: NextPageContext) => {
return !!(ctx && ctx.res && ctx.res.writeHead);
};
const isStaticRenderCtx = (ctx?: NextPageContext) => {
return !!(ctx && ctx.res && !ctx.res.writeHead);
};
const isClientRender = () => {
return typeof window !== undefined;
};
const PrivatePage: NextPage = () => {
return (
<>
<div>Seeing a private page.</div>
<div>
<Link href="/vns/debug/public">
<a>Back to public page</a>
</Link>
</div>
</>
);
};
// NOTE: we use getInitialProps to demo redirect, in order to keep things consistent
// with _app, that do not support getServerSideProps and getStaticProps at the time of writing (Next 9.4)
// When redirecting in a page, you could achieve a cleaner setup using getServerSideProps (not demonstrated here)
PrivatePage.getInitialProps = async (ctx?: NextPageContext) => {
debugNext("Running page getInitialProps");
const namespacesRequired = ["common"]; // i18n
// We simulate private connexion
const isAllowed = !!ctx.query.allowed; // demo
const pageProps = { namespacesRequired, isAllowed };
if (isAllowed) {
return { ...pageProps, isAllowed };
}
if (isStaticRenderCtx(ctx)) {
debugNext("Detected static render, not doing anything");
// Scenario 1: we are in a static export
// We do not do anything
} else if (isServerSideRenderCtx(ctx)) {
// Scenario 2: we are in a server-side render
debugNext("Detected dynamic server-side rendering");
debugNext("Redirecting (dynamic server render)");

redirectServer(ctx)("/vns/debug/public");
} else if (isClientRender()) {
// Scenario 3: we are client-side
debugNext("Detected client render");
debugNext("Redirecting (client-side)");

Router.push("/vns/debug/public");
}
return pageProps;
};
export default PrivatePage;
49 changes: 16 additions & 33 deletions src/pages/vns/debug/private.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
*/
import Link from "next/link";
import { NextPage, NextPageContext } from "next";
import Router from "next/router";
import Router, { useRouter } from "next/router";
import debug from "debug";
import { useEffect } from "react";
const debugNext = debug("vns:next");

// @ssr-only
Expand All @@ -24,7 +25,15 @@ const isStaticRenderCtx = (ctx?: NextPageContext) => {
const isClientRender = () => {
return typeof window !== undefined;
};
const PrivatePage: NextPage = () => {

interface PrivatePageProps {
isAllowed: boolean;
}
const PrivatePage: NextPage<PrivatePageProps> = (props) => {
//const router = useRouter();
//const { isAllowed } = props;
//if (!isAllowed) {
//}
return (
<>
<h1>private</h1>
Expand All @@ -37,39 +46,13 @@ const PrivatePage: NextPage = () => {
</>
);
};
// NOTE: we use getInitialProps to demo redirect, in order to keep things consistent
// with _app, that do not support getServerSideProps and getStaticProps at the time of writing (Next 9.4)
// When redirecting in a page, you could achieve a cleaner setup using getServerSideProps (not demonstrated here)
PrivatePage.getInitialProps = async (ctx?: NextPageContext) => {
debugNext("Running page getInitialProps");
const namespacesRequired = ["common"]; // i18n
// We simulate private connexion
const isAllowed = !!ctx.query.allowed; // demo
const pageProps = { namespacesRequired, isAllowed };
if (isAllowed) {
return { ...pageProps, isAllowed };
}
if (isStaticRenderCtx(ctx)) {
debugNext("Detected static render, not doing anything");
// Scenario 1: we are in a static export
// => we should not static render the page
// TODO
} else if (isServerSideRenderCtx(ctx)) {
// Scenario 2: we are in a server-side render
debugNext("Detected dynamic server-side rendering");
debugNext("Redirecting (dynamic server render)");

export const getServerSideProps = async (ctx: NextPageContext) => {
const isAllowed = !!ctx.query.allowed; // demo
if (!isAllowed) {
debugNext("Redirecting (dynamic server render)", ctx.req.url);
redirectServer(ctx)("/vns/debug/public");
} else if (isClientRender()) {
// Scenario 3: we are client-side
debugNext("Detected client render");
debugNext("Redirecting (client-side)");

Router.push("/vns/debug/public");
}
return pageProps;

// => we redirect using HTTP
// Scenario 4: we are server-side, called client-side during routing
return { props: { isAllowed } };
};
export default PrivatePage;
25 changes: 25 additions & 0 deletions src/pages/vns/debug/public.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import Link from "next/link";
import { useRouter } from "next/router";
const PublicPage = () => {
const router = useRouter();
return (
<>
<h1>public</h1>
Expand All @@ -14,13 +16,36 @@ const PublicPage = () => {
</a>
</Link>
</div>
<div>
<button
className="private-shallow"
onClick={() => {
router.push("/vns/debug/private", undefined, { shallow: true });
}}
>
Link to a private page, shallow redirect, should redirect you back
here
</button>
</div>
<div>
<Link href="/vns/debug/private?allowed=true">
<a className="private-allowed">
Link to a private page, should not redirect you
</a>
</Link>
</div>
<div>
<button
className="private-allowed-shallow"
onClick={() => {
router.push("/vns/debug/private?allowed=true", undefined, {
shallow: true,
});
}}
>
Link to a private page, shallow redirect, should not redirect you
</button>
</div>
</>
);
};
Expand Down

0 comments on commit 564840d

Please sign in to comment.