Authenticate UI
This commit is contained in:
+7
-3
@@ -1,13 +1,17 @@
|
||||
// in src/App.js
|
||||
import React from 'react'
|
||||
import { Admin, Resource } from 'react-admin'
|
||||
import jsonServerProvider from 'ra-data-json-server'
|
||||
import dataProvider from './dataProvider'
|
||||
import authProvider from './authProvider'
|
||||
import { Login } from './layout'
|
||||
import user from './user'
|
||||
|
||||
const dataProvider = jsonServerProvider('/app/api')
|
||||
const App = () => (
|
||||
<Admin dataProvider={dataProvider} loginPage={Login}>
|
||||
<Admin
|
||||
dataProvider={dataProvider}
|
||||
authProvider={authProvider}
|
||||
loginPage={Login}
|
||||
>
|
||||
<Resource name="user" {...user} />
|
||||
</Admin>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import jwtDecode from 'jwt-decode'
|
||||
|
||||
const authProvider = {
|
||||
login: ({ username, password }) => {
|
||||
const request = new Request('/app/login', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ username, password }),
|
||||
headers: new Headers({ 'Content-Type': 'application/json' })
|
||||
})
|
||||
return fetch(request)
|
||||
.then((response) => {
|
||||
if (response.status < 200 || response.status >= 300) {
|
||||
throw new Error(response.statusText)
|
||||
}
|
||||
return response.json()
|
||||
})
|
||||
.then((response) => {
|
||||
// Validate token
|
||||
jwtDecode(response.token)
|
||||
localStorage.setItem('token', response.token)
|
||||
localStorage.setItem('name', response.name)
|
||||
localStorage.setItem('username', response.username)
|
||||
return response
|
||||
})
|
||||
.catch((error) => {
|
||||
if (
|
||||
error.message === 'Failed to fetch' ||
|
||||
error.stack === 'TypeError: Failed to fetch'
|
||||
) {
|
||||
throw new Error('errors.network_error')
|
||||
}
|
||||
|
||||
throw new Error(error)
|
||||
})
|
||||
},
|
||||
|
||||
logout: () => {
|
||||
removeItems()
|
||||
return Promise.resolve()
|
||||
},
|
||||
|
||||
checkAuth: () => {
|
||||
try {
|
||||
const expireTime = jwtDecode(localStorage.getItem('token')).exp * 1000
|
||||
const now = new Date().getTime()
|
||||
return now < expireTime ? Promise.resolve() : Promise.reject()
|
||||
} catch (e) {
|
||||
return Promise.reject()
|
||||
}
|
||||
},
|
||||
|
||||
checkError: (error) => {
|
||||
const { status } = error
|
||||
// TODO Remove 403?
|
||||
if (status === 401 || status === 403) {
|
||||
removeItems()
|
||||
return Promise.reject()
|
||||
}
|
||||
return Promise.resolve()
|
||||
},
|
||||
|
||||
getPermissions: (params) => Promise.resolve()
|
||||
}
|
||||
|
||||
const removeItems = () => {
|
||||
localStorage.removeItem('token')
|
||||
localStorage.removeItem('name')
|
||||
localStorage.removeItem('username')
|
||||
}
|
||||
|
||||
export default authProvider
|
||||
@@ -0,0 +1,23 @@
|
||||
import { fetchUtils } from 'react-admin'
|
||||
import jsonServerProvider from 'ra-data-json-server'
|
||||
|
||||
const httpClient = (url, options = {}) => {
|
||||
if (!options.headers) {
|
||||
options.headers = new Headers({ Accept: 'application/json' })
|
||||
}
|
||||
const token = localStorage.getItem('token')
|
||||
if (token) {
|
||||
options.headers.set('Authorization', `Bearer ${token}`)
|
||||
}
|
||||
return fetchUtils.fetchJson(url, options).then((response) => {
|
||||
const token = response.headers.get('authorization')
|
||||
if (token) {
|
||||
localStorage.setItem('token', token)
|
||||
}
|
||||
return response
|
||||
})
|
||||
}
|
||||
|
||||
const dataProvider = jsonServerProvider('/app/api', httpClient)
|
||||
|
||||
export default dataProvider
|
||||
@@ -5,13 +5,16 @@ import {
|
||||
TextInput,
|
||||
PasswordInput,
|
||||
required,
|
||||
email,
|
||||
SimpleForm
|
||||
} from 'react-admin'
|
||||
|
||||
const UserCreate = (props) => (
|
||||
<Create {...props}>
|
||||
<SimpleForm redirect="list">
|
||||
<TextInput source="userName" validate={[required()]} />
|
||||
<TextInput source="name" validate={[required()]} />
|
||||
<TextInput source="email" validate={[required(), email()]} />
|
||||
<PasswordInput source="password" validate={[required()]} />
|
||||
<BooleanInput source="isAdmin" initialValue={false} />
|
||||
</SimpleForm>
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
PasswordInput,
|
||||
Edit,
|
||||
required,
|
||||
email,
|
||||
SimpleForm
|
||||
} from 'react-admin'
|
||||
|
||||
@@ -15,7 +16,9 @@ const UserTitle = ({ record }) => {
|
||||
const UserEdit = (props) => (
|
||||
<Edit title={<UserTitle />} {...props}>
|
||||
<SimpleForm>
|
||||
<TextInput source="userName" validate={[required()]} />
|
||||
<TextInput source="name" validate={[required()]} />
|
||||
<TextInput source="email" validate={[required(), email()]} />
|
||||
<PasswordInput source="password" validate={[required()]} />
|
||||
<BooleanInput source="isAdmin" initialValue={false} />
|
||||
<DateField source="lastLoginAt" />
|
||||
|
||||
@@ -23,7 +23,7 @@ const UserList = (props) => {
|
||||
return (
|
||||
<List
|
||||
{...props}
|
||||
sort={{ field: 'name', order: 'ASC' }}
|
||||
sort={{ field: 'userName', order: 'ASC' }}
|
||||
exporter={false}
|
||||
filters={<UserFilter />}
|
||||
>
|
||||
@@ -34,9 +34,8 @@ const UserList = (props) => {
|
||||
/>
|
||||
) : (
|
||||
<Datagrid rowClick="edit">
|
||||
<TextField source="name" />
|
||||
<TextField source="userName" />
|
||||
<BooleanField source="isAdmin" />
|
||||
<DateField source="lastLoginAt" locales="pt-BR" />
|
||||
<DateField source="lastAccessAt" locales="pt-BR" />
|
||||
<DateField source="updatedAt" locales="pt-BR" />
|
||||
</Datagrid>
|
||||
|
||||
Reference in New Issue
Block a user