Ajout page d'authentification

This commit is contained in:
wpetit 2020-02-19 12:21:04 +01:00
parent 72e328ea1c
commit 3aa8ab987b
9 changed files with 203 additions and 14 deletions

View File

@ -2,6 +2,7 @@
namespace App\Controller;
use App\Http\DataResponse;
use App\Http\ErrorResponse;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
@ -12,10 +13,19 @@ class SecurityController extends Controller
/**
* @Route("/api/v1/login", name="api_v1_login", methods={"POST"})
*/
public function login(Request $request)
public function login()
{
$user = $this->getUser();
if ($user == null) {
return new ErrorResponse(
0,
"Identifiants invalides",
null,
401,
);
}
return new DataResponse([
'username' => $user->getUsername(),
'roles' => $user->getRoles(),

View File

@ -5107,7 +5107,8 @@
},
"ansi-regex": {
"version": "2.1.1",
"bundled": true
"bundled": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
@ -5125,11 +5126,13 @@
},
"balanced-match": {
"version": "1.0.0",
"bundled": true
"bundled": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -5142,15 +5145,18 @@
},
"code-point-at": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@ -5253,7 +5259,8 @@
},
"inherits": {
"version": "2.0.4",
"bundled": true
"bundled": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@ -5263,6 +5270,7 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -5275,17 +5283,20 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
"bundled": true
"bundled": true,
"optional": true
},
"minipass": {
"version": "2.9.0",
"bundled": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -5302,6 +5313,7 @@
"mkdirp": {
"version": "0.5.1",
"bundled": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -5382,7 +5394,8 @@
},
"number-is-nan": {
"version": "1.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@ -5392,6 +5405,7 @@
"once": {
"version": "1.4.0",
"bundled": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -5467,7 +5481,8 @@
},
"safe-buffer": {
"version": "5.1.2",
"bundled": true
"bundled": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@ -5497,6 +5512,7 @@
"string-width": {
"version": "1.0.2",
"bundled": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -5514,6 +5530,7 @@
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -5552,11 +5569,13 @@
},
"wrappy": {
"version": "1.0.2",
"bundled": true
"bundled": true,
"optional": true
},
"yallist": {
"version": "3.1.1",
"bundled": true
"bundled": true,
"optional": true
}
}
},

View File

@ -0,0 +1,31 @@
export const LOGIN_REQUEST = 'LOGIN_REQUEST'
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
export const LOGIN_FAILURE = 'LOGIN_FAILURE';
export function login(username, password) {
return { type: LOGIN_REQUEST, username, password }
}
export function loginFailure(username, error) {
return { type: LOGIN_FAILURE, username, error }
}
export function loginSuccess(username) {
return { type: LOGIN_SUCCESS, username }
}
export const LOGOUT_REQUEST = 'LOGOUT_REQUEST'
export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS';
export const LOGOUT_FAILURE = 'LOGOUT_FAILURE';
export function logout(username, password) {
return { type: LOGOUT_REQUEST, username, password }
}
export function logoutFailure(username, error) {
return { type: LOGOUT_FAILURE, username, error }
}
export function logoutSuccess(username) {
return { type: LOGOUT_SUCCESS, username }
}

View File

@ -3,6 +3,7 @@ import { hot } from 'react-hot-loader'
import { HashRouter } from 'react-router-dom' // ou BrowserRouter
import { Route, Switch, Redirect } from 'react-router'
import HomePage from './pages/home';
import { ConnectedLoginPage as LoginPage } from './pages/login';
class App extends Component {
render () {
@ -10,6 +11,7 @@ class App extends Component {
<Fragment>
<HashRouter>
<Switch>
<Route path='/login' exact component={LoginPage} />
<Route path='/home' exact component={HomePage} />
<Route component={() => <Redirect to="/home" />} />
</Switch>

View File

@ -0,0 +1,67 @@
import React, { useState, useEffect } from 'react'
import Page from './page';
import { login } from '../actions/auth.actions';
import { connect } from 'react-redux';
export function LoginPage({ dispatch, isLoggedIn, history }) {
const [ formData, setFormData ] = useState({username: '', password: ''});
const onUsernameChange = evt => setFormData({ ...formData, username: evt.target.value });
const onPasswordChange = evt => setFormData({ ...formData, password: evt.target.value });
const onSubmit = evt => {
evt.preventDefault();
const { username, password } = formData;
dispatch(login(username, password));
}
useEffect(() => {
if (isLoggedIn) history.push('/home');
}, [isLoggedIn]);
return (
<Page>
<div className="section">
<div className="columns">
<div className="column is-4 is-offset-4">
<div className="box">
<div className="field">
<label className="label">Nom d'utilisateur</label>
<div className="control">
<input
value={formData.username}
onChange={onUsernameChange}
type="text" className="input" />
</div>
</div>
<div className="field">
<label className="label">Mot de passe</label>
<div className="control">
<input
value={formData.password}
onChange={onPasswordChange}
className="input" type="password" />
</div>
</div>
<div className="field is-grouped is-grouped-right">
<p className="control">
<button onClick={onSubmit}
className="button is-primary">
Se connecter
</button>
</p>
</div>
</div>
</div>
</div>
</div>
</Page>
);
}
function mapStateToProps({ session }) {
return { isLoggedIn: session.isLoggedIn };
}
export const ConnectedLoginPage = connect(mapStateToProps)(LoginPage);

View File

@ -0,0 +1,24 @@
import { LOGIN_SUCCESS } from "../actions/auth.actions";
const initialState = {
isLoggedIn: false,
user: null,
};
export function sessionReducer(state = initialState, action) {
switch(action.type) {
case LOGIN_SUCCESS:
return handleLoginSuccess(state, action);
};
return state;
}
function handleLoginSuccess(state, action) {
return {
...state.user,
isLoggedIn: true,
user: {
username: action.username,
},
}
};

View File

@ -0,0 +1,33 @@
import { call, put } from 'redux-saga/effects';
import { loginFailure, loginSuccess } from '../actions/auth.actions';
export function* loginSaga(action) {
let result;
try {
result = yield call(doLogin, action.username, action.password);
} catch(err) {
yield put(loginFailure(action.username, err));
}
if ('error' in result) {
yield put(loginFailure(action.username, result.error));
return
}
yield put(loginSuccess(action.username));
}
function doLogin(username, password) {
return fetch('http://localhost:8001/api/v1/login', {
method: 'POST',
body: JSON.stringify({
username: username,
password: password
}),
headers: {
'Content-Type': 'application/json',
},
mode: 'cors',
credentials: 'include'
}).then(res => res.json())
}

View File

@ -1,7 +1,9 @@
import { all, takeLatest } from 'redux-saga/effects';
import { LOGIN_REQUEST } from '../actions/auth.actions';
import { loginSaga} from './auth.sagas';
export default function* rootSaga() {
yield all([
takeLatest(LOGIN_REQUEST, loginSaga),
]);
}

View File

@ -1,11 +1,12 @@
import { createStore, applyMiddleware, combineReducers, compose } from 'redux'
import createSagaMiddleware from 'redux-saga'
import rootSaga from '../sagas/root'
import { sessionReducer } from '../reducers/session.reducers';
const sagaMiddleware = createSagaMiddleware()
const rootReducer = combineReducers({
// Ajouter vos reducers ici
session: sessionReducer,
});
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;