Implement login and logout with JWT

This commit is contained in:
Jan Tuomi
2019-01-15 15:40:14 +02:00
parent 843544d65d
commit 2981879b2e
10 changed files with 167 additions and 2 deletions
+5
View File
@@ -9146,6 +9146,11 @@
"integrity": "sha512-aUnNwqMOXw3yvErjMPSQu6qIIzUmT1e5KcU1OZxRDU1g/am6mzBvcrmLAYwzmB59BHPrh5/tKaiF4OPhqRWESQ==",
"dev": true
},
"js-cookie": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.0.tgz",
"integrity": "sha1-Gywnmm7s44ChIWi5JIUmWzWx7/s="
},
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+1
View File
@@ -94,6 +94,7 @@
},
"dependencies": {
"axios": "^0.18.0",
"js-cookie": "^2.2.0",
"mobx": "^5.0.3",
"mobx-react": "^5.2.3",
"normalize.css": "^8.0.0",
+29
View File
@@ -0,0 +1,29 @@
import axios from "axios";
import * as Cookies from "js-cookie";
const url = `${process.env.API_URL}/api-token-auth/`;
export async function generateToken(username: string, password: string): Promise<string> {
try {
const resp = await axios.post(url, {
username,
password,
});
return resp.data["token"];
} catch (err) {
console.error(err);
throw err;
}
}
export function setTokenCookie(token: string) {
Cookies.set("jwt", token);
}
export function getTokenCookie(): string {
return Cookies.get("jwt");
}
export function deleteTokenCookie(): string {
return Cookies.remove("jwt");
}
@@ -15,6 +15,7 @@ class AdminSidebar extends React.Component<AdminSiderbarProps, AdminSiderbarStat
<div className="admin-sidebar">
<AdminSidebarLink to="/admin" path={path}>Home</AdminSidebarLink>
<AdminSidebarLink to="/admin/events" path={path}>Events</AdminSidebarLink>
<AdminSidebarLink to="/admin/logout" path={path}>Logout</AdminSidebarLink>
</div>
);
}
@@ -0,0 +1,5 @@
.admin-login-page {
input {
display: block;
}
}
@@ -0,0 +1,81 @@
import * as React from "react";
import Helmet from "react-helmet";
import { Redirect } from "react-router-dom";
import { generateToken, setTokenCookie, getTokenCookie } from "../../auth";
import "./AdminLoginPage.scss";
export interface AdminLoginPageProps {
history: {
push: (to: string) => void;
};
}
export interface AdminLoginPageState {
username: string;
password: string;
existingToken: string;
}
class AdminLoginPage extends React.Component<AdminLoginPageProps, AdminLoginPageState> {
constructor(props) {
super(props);
this.state = {
username: "",
password: "",
existingToken: getTokenCookie(),
};
}
handleSubmit = async (e) => {
e.preventDefault();
const { username, password } = this.state;
const { history } = this.props;
try {
const token = await generateToken(username, password);
console.log("JWT token:", token);
setTokenCookie(token);
history.push("/admin");
} catch (err) {
console.error("Failed to log in!");
}
}
handleUserNameChange = (e) => {
this.setState({
username: e.target.value,
});
}
handlePasswordChange = (e) => {
this.setState({
password: e.target.value,
});
}
render() {
const { username, password, existingToken } = this.state;
if (existingToken) {
return <Redirect to="/admin" />;
}
return (
<div className="admin-login-page">
<Helmet>
<link rel="canonical" href="https://sik.ayy.fi/admin/login" />
</Helmet>
<form onSubmit={this.handleSubmit}>
<label>Username
<input type="text" name="username" value={username} onChange={this.handleUserNameChange} />
</label>
<label>Password
<input type="password" name="password" value={password} onChange={this.handlePasswordChange} />
</label>
<input type="submit" />
</form>
</div>
);
}
}
export default AdminLoginPage;
+2
View File
@@ -0,0 +1,2 @@
import AdminLoginPage from "./AdminLoginPage";
export default AdminLoginPage;
@@ -0,0 +1,21 @@
import * as React from "react";
import { Redirect } from "react-router-dom";
import { deleteTokenCookie } from "../../auth";
export interface AdminLogoutPageProps {}
export interface AdminLogoutPageState {}
class AdminLogoutPage extends React.Component<AdminLogoutPageProps, AdminLogoutPageState> {
constructor(props) {
super(props);
deleteTokenCookie();
}
render() {
return (
<Redirect to="/admin/login" />
);
}
}
export default AdminLogoutPage;
+2
View File
@@ -0,0 +1,2 @@
import AdminLogoutPage from "./AdminLogoutPage";
export default AdminLogoutPage;
+20 -2
View File
@@ -1,6 +1,6 @@
import * as React from "react";
import { Fragment } from "react";
import { Switch, Route, DefaultRoute } from "react-router-dom";
import { Switch, Route, Redirect } from "react-router-dom";
import Helmet from "react-helmet";
import FrontPage from "./pages/FrontPage";
import GuildPage from "./pages/GuildPage";
@@ -11,22 +11,39 @@ import "./index.scss";
import AdminFrontPage from "./pages/AdminFrontPage";
import AdminEventPage from "./pages/AdminEventPage";
import AdminCommonPage from "./pages/AdminCommonPage";
import AdminLoginPage from "./pages/AdminLoginPage";
import { getTokenCookie } from "./auth";
import AdminLogoutPage from "./pages/AdminLogoutPage";
const renderPage = (Page) => (props): JSX.Element => {
return <CommonPage page={Page} {...props} />;
};
const renderAdminPage = (Page) => (props): JSX.Element => {
const renderAdminLoginPage = (Page) => (props): JSX.Element => {
return <AdminCommonPage page={Page} {...props} />;
};
const renderAdminPage = (Page) => (props): JSX.Element => {
const token = getTokenCookie();
if (token) {
return <AdminCommonPage page={Page} {...props} />;
} else {
return <Redirect to="/admin/login" />;
}
};
const commonRoutes = [
{ path: "/", page: FrontPage },
{ path: "/kilta", page: GuildPage },
];
const adminLoginRoutes = [
{ path: "/admin/login", page: AdminLoginPage },
];
const adminRoutes = [
{ path: "/admin/events", page: AdminEventPage },
{ path: "/admin/logout", page: AdminLogoutPage },
{ path: "/admin", page: AdminFrontPage },
];
@@ -45,6 +62,7 @@ const Routes = () => (
}} />
<Switch>
{ commonRoutes.map(r => <Route key={r.path} exact path={r.path} render={renderPage(r.page) }/>) }
{ adminLoginRoutes.map(r => <Route key={r.path} exact path={r.path} render={renderAdminLoginPage(r.page) }/>) }
{ adminRoutes.map(r => <Route key={r.path} exact path={r.path} render={renderAdminPage(r.page) }/>) }
<Route component={NotFoundPage} />
</Switch>