Max/Backend/loginApi Ajout mock Users et Tokens #62
@ -21,6 +21,7 @@ dependencies {
|
||||
implementation("org.springframework.boot:spring-boot-starter-mail")
|
||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||
implementation("org.springframework.boot:spring-boot-starter-security")
|
||||
implementation("com.kohlschutter.junixsocket:junixsocket-core:2.9.0")
|
||||
// implementation("org.springframework.session:spring-session-jdbc")
|
||||
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||
|
@ -2,8 +2,9 @@ package ovh.herisson.Clyde;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
|
||||
@SpringBootApplication
|
||||
@SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
|
||||
public class ClydeApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
@ -0,0 +1,31 @@
|
||||
package ovh.herisson.Clyde.EndPoints;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import ovh.herisson.Clyde.Responses.UnauthorizedResponse;
|
||||
import ovh.herisson.Clyde.Services.AuthenticatorService;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin(origins = "http://localhost:5173")
|
||||
public class LoginController {
|
||||
private final AuthenticatorService authServ;
|
||||
public LoginController(AuthenticatorService authServ){
|
||||
this.authServ = authServ;
|
||||
}
|
||||
@PostMapping("/login")
|
||||
public ResponseEntity<String> login(@RequestParam String identifier, String password, Date expirationDate){
|
||||
|
||||
String sessionToken = authServ.login(identifier,password,expirationDate);
|
||||
if (sessionToken == null){
|
||||
return new UnauthorizedResponse<>("Identifier or Password incorrect");
|
||||
}
|
||||
|
||||
HttpHeaders responseHeaders = new HttpHeaders();
|
||||
responseHeaders.set("Set-Cookie",String.format("session_token=%s",sessionToken));
|
||||
return ResponseEntity.ok().headers(responseHeaders).build();
|
||||
}
|
||||
Maxime marked this conversation as resolved
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,65 @@
|
||||
package ovh.herisson.Clyde.EndPoints;
|
||||
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import ovh.herisson.Clyde.Repositories.TokenRepository;
|
||||
import ovh.herisson.Clyde.Repositories.UserRepository;
|
||||
import ovh.herisson.Clyde.Tables.Role;
|
||||
import ovh.herisson.Clyde.Tables.Token;
|
||||
import ovh.herisson.Clyde.Tables.User;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin(origins = "http://localhost:5173")
|
||||
|
||||
public class MockController {
|
||||
private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
|
||||
public final UserRepository userRepo;
|
||||
public final TokenRepository tokenRepo;
|
||||
|
||||
ArrayList<User> mockUsers;
|
||||
|
||||
|
||||
public MockController(UserRepository userRepo, TokenRepository tokenRepo){
|
||||
this.tokenRepo = tokenRepo;
|
||||
this.userRepo = userRepo;
|
||||
}
|
||||
|
||||
/** Saves an example of each user type by :
|
||||
* email : FooRole@FooRole.com, password : FooRole and token : FooRole
|
||||
* For example the admin as "admin@admin.com" as email and "admin" as both password and token
|
||||
* They all have silly names
|
||||
*/
|
||||
|
||||
@PostMapping("/mock")
|
||||
public void postMock(){
|
||||
|
||||
User herobrine = new User("brine","hero","admin@admin.com","in your WalLs","ShadowsLand",new Date(0), "none",Role.Admin,passwordEncoder.encode("admin"));
|
||||
User joe = new User("Mama","Joe","student@student.com","roundabout","DaWarudo",new Date(0), "None",Role.Student,passwordEncoder.encode("student"));
|
||||
User meh = new User("Inspiration","lackOf","secretary@secretary.com","a Box","the street",new Date(0),"none", Role.Teacher,passwordEncoder.encode("secretary"));
|
||||
User joke = new User("CthemBalls","Lemme","teacher@teacher.com","lab","faculty",new Date(0), "none",Role.Teacher,passwordEncoder.encode("teacher"));
|
||||
|
||||
mockUsers = new ArrayList<User>(Arrays.asList(herobrine,joe,meh,joke));
|
||||
|
||||
userRepo.saveAll(mockUsers);
|
||||
|
||||
for (User user: mockUsers){
|
||||
tokenRepo.save(new Token(user,user.getPassword()));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/mock")
|
||||
public void deleteMock(){
|
||||
for (User user:mockUsers){
|
||||
tokenRepo.deleteAll(tokenRepo.getByUser(user));
|
||||
}
|
||||
userRepo.deleteAll(mockUsers);
|
||||
}
|
||||
}
|
@ -2,10 +2,12 @@ package ovh.herisson.Clyde.EndPoints;
|
||||
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import ovh.herisson.Clyde.Repositories.UserRepository;
|
||||
import ovh.herisson.Clyde.Responses.UnauthorizedResponse;
|
||||
import ovh.herisson.Clyde.Services.AuthenticatorService;
|
||||
import ovh.herisson.Clyde.Services.UserService;
|
||||
import ovh.herisson.Clyde.Tables.User;
|
||||
|
||||
|
||||
@ -13,30 +15,31 @@ import ovh.herisson.Clyde.Tables.User;
|
||||
@CrossOrigin(origins = "http://localhost:5173")
|
||||
public class UserController {
|
||||
Maxime marked this conversation as resolved
tonitch
commented
il ne faut pas un @RestController ? il ne faut pas un @RestController ?
Maxime
commented
si si
|
||||
|
||||
private final UserRepository userRepo;
|
||||
|
||||
public UserController(UserRepository userRepo){
|
||||
this.userRepo = userRepo;
|
||||
private final UserService userService;
|
||||
private final AuthenticatorService authServ;
|
||||
public UserController(UserService userService, AuthenticatorService authServ){
|
||||
this.userService = userService;
|
||||
this.authServ = authServ;
|
||||
}
|
||||
Maxime marked this conversation as resolved
Outdated
tonitch
commented
l’espace après le = l’espace après le =
s'il
te
plait
...
|
||||
|
||||
@GetMapping("/user")
|
||||
public ResponseEntity<User> getUsers(@RequestHeader("Authorization") String token){
|
||||
//TODO
|
||||
// Get the token thru the data base
|
||||
// tokenRepo.findToken(token) => User userFromToken
|
||||
// si role != secretary => return error : ResponseEntity<User>(null, HttpStatus.UNAUTHORIZED)
|
||||
return new ResponseEntity<User>(/**userRepo.findById(userFromToken.id),**/ HttpStatus.OK);
|
||||
public ResponseEntity<User> getUser(@RequestHeader("Authorization") String token){
|
||||
User user = authServ.getUserFromToken(token);
|
||||
if (user == null) {
|
||||
return new UnauthorizedResponse<>(null);
|
||||
}
|
||||
return new ResponseEntity<>(user, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@PostMapping("/user")
|
||||
public ResponseEntity<String> postUser(@RequestBody User user){
|
||||
userRepo.save(user);
|
||||
userService.save(user);
|
||||
return new ResponseEntity<String>(String.format("Account created with ID:%s",user.getRegNo()),HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@GetMapping("/users")
|
||||
public Iterable<User> getAllUsers(){//TODO ne l'accepter que si c'est le secrétariat
|
||||
return userRepo.findAll();
|
||||
public Iterable<User> getAllUsers(){
|
||||
return userService.getAll();
|
||||
}
|
||||
|
||||
|
||||
|
@ -6,8 +6,6 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class JdbcConfig {
|
||||
|
@ -0,0 +1,12 @@
|
||||
package ovh.herisson.Clyde.Repositories;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import ovh.herisson.Clyde.Tables.Token;
|
||||
import ovh.herisson.Clyde.Tables.User;
|
||||
|
||||
public interface TokenRepository extends CrudRepository<Token,Long> {
|
||||
|
||||
Token getByToken(String token);
|
||||
|
||||
Iterable<Token> getByUser(User user);
|
||||
}
|
@ -10,6 +10,8 @@ public interface UserRepository extends CrudRepository<User, Long> {
|
||||
|
||||
User findById(long id);
|
||||
|
||||
User findByEmail(String email);
|
||||
|
||||
/**
|
||||
@Query(value = "select a.* from Users a ",nativeQuery = true)
|
||||
Iterable<User> findAllUsers();**/
|
||||
|
@ -0,0 +1,12 @@
|
||||
package ovh.herisson.Clyde.Responses;
|
||||
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
|
||||
public class UnauthorizedResponse<T> extends ResponseEntity<T> {
|
||||
public UnauthorizedResponse(T message) {
|
||||
super(message,HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package ovh.herisson.Clyde.Services;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import ovh.herisson.Clyde.Tables.User;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Service
|
||||
public class AuthenticatorService {
|
||||
|
||||
private final TokenService tokenService;
|
||||
private final UserService userService;
|
||||
|
||||
public AuthenticatorService(TokenService tokenService, UserService userService){
|
||||
this.tokenService = tokenService;
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
public User getUserFromToken(String token){
|
||||
return tokenService.getUserFromToken(token);
|
||||
}
|
||||
|
||||
|
||||
public String login(String identifier, String password, Date expirationDate){
|
||||
User user = userService.getUser(identifier);
|
||||
if (user == null){return null;}
|
||||
if (!userService.checkPassword(user,password)){return null;}
|
||||
String token = tokenService.generateNewToken();
|
||||
tokenService.saveToken(token,user,expirationDate);
|
||||
return token;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package ovh.herisson.Clyde.Services;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import ovh.herisson.Clyde.Repositories.TokenRepository;
|
||||
import ovh.herisson.Clyde.Tables.Token;
|
||||
import ovh.herisson.Clyde.Tables.User;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Date;
|
||||
|
||||
@Service
|
||||
public class TokenService {
|
||||
|
||||
TokenRepository tokenRepo;
|
||||
|
||||
public TokenService(TokenRepository tokenRepo){
|
||||
this.tokenRepo = tokenRepo;
|
||||
}
|
||||
|
||||
|
||||
public String generateNewToken(){
|
||||
byte[] bytes = new byte[64];
|
||||
new SecureRandom().nextBytes(bytes);
|
||||
String token = new String(bytes, StandardCharsets.US_ASCII);
|
||||
System.out.println(token);
|
||||
return token;
|
||||
}
|
||||
|
||||
public User getUserFromToken(String token){
|
||||
return tokenRepo.getByToken(token).getUser();
|
||||
}
|
||||
|
||||
public void saveToken(String token, User user, Date expirationDate){// todo faire qlq chose de l'expDate
|
||||
tokenRepo.save(new Token(user,token));
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package ovh.herisson.Clyde.Services;
|
||||
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ovh.herisson.Clyde.Repositories.UserRepository;
|
||||
import ovh.herisson.Clyde.Tables.Role;
|
||||
import ovh.herisson.Clyde.Tables.User;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class UserService {
|
||||
|
||||
private final UserRepository userRepo;
|
||||
private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
|
||||
public UserService(UserRepository userRepo){
|
||||
this.userRepo = userRepo;
|
||||
}
|
||||
|
||||
|
||||
public User getUser(String identifier){
|
||||
if (identifier == null) return null;
|
||||
try {
|
||||
int id = Integer.parseInt(identifier);
|
||||
return userRepo.findById(id);
|
||||
}
|
||||
catch (NumberFormatException nfe){
|
||||
return userRepo.findByEmail(identifier);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean checkPassword(User user, String tryingPassword){
|
||||
return passwordEncoder.matches(tryingPassword, user.getPassword());
|
||||
}
|
||||
|
||||
public void save(User user){
|
||||
userRepo.save(user);
|
||||
}
|
||||
|
||||
public Iterable<User> getAll(){
|
||||
return userRepo.findAll();
|
||||
}
|
||||
|
||||
}
|
@ -8,15 +8,17 @@ public class CursusCourse {
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private int id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "Cursus")
|
||||
private int cursusId;
|
||||
private Cursus cursus;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "Course")
|
||||
private int courseId;
|
||||
private Course course;
|
||||
|
||||
public CursusCourse(int cursusId, int courseId){
|
||||
this.cursusId = cursusId;
|
||||
this.courseId = courseId;
|
||||
public CursusCourse(Cursus cursus, Course course){
|
||||
this.cursus = cursus;
|
||||
this.course = course;
|
||||
}
|
||||
|
||||
public CursusCourse() {}
|
||||
@ -25,19 +27,19 @@ public class CursusCourse {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getCourseId() {
|
||||
return courseId;
|
||||
public Course getCourse() {
|
||||
return course;
|
||||
}
|
||||
|
||||
public void setCourseId(int courseId){
|
||||
this.courseId = courseId;
|
||||
public void setCourse(Course course){
|
||||
this.course = course;
|
||||
}
|
||||
|
||||
public int getCursusId() {
|
||||
return cursusId;
|
||||
public Cursus getCursus() {
|
||||
return cursus;
|
||||
}
|
||||
|
||||
public void setCursusId(int cursusId) {
|
||||
this.cursusId = cursusId;
|
||||
public void setCursus(Cursus cursus) {
|
||||
this.cursus = cursus;
|
||||
}
|
||||
}
|
||||
|
@ -8,12 +8,13 @@ public class Secretary {
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private int id;
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "Users")
|
||||
private int regNo;
|
||||
private User user;
|
||||
private String faculty;
|
||||
|
||||
public Secretary(int regNo, String faculty){
|
||||
this.regNo = regNo;
|
||||
public Secretary(User user, String faculty){
|
||||
this.user = user;
|
||||
this.faculty = faculty;
|
||||
}
|
||||
|
||||
@ -23,12 +24,12 @@ public class Secretary {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getRegNo() {
|
||||
return regNo;
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setRegNo(int regNo) {
|
||||
this.regNo = regNo;
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public String getFaculty() {
|
||||
|
@ -8,18 +8,21 @@ public class TeacherGivenCourse {
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private int id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "Users")
|
||||
private int regNo;
|
||||
private User user;
|
||||
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "Course")
|
||||
private int courseId;
|
||||
private Course course;
|
||||
|
||||
//This flag helps make the difference between an assistant or a Teacher (who owns the course)
|
||||
private boolean owned;
|
||||
|
||||
public TeacherGivenCourse(int regNo, int courseId, boolean owned){
|
||||
this.regNo = regNo;
|
||||
this.courseId = courseId;
|
||||
public TeacherGivenCourse(User user, Course course, boolean owned){
|
||||
this.user = user;
|
||||
this.course = course;
|
||||
this.owned = owned;
|
||||
}
|
||||
|
||||
@ -29,20 +32,20 @@ public class TeacherGivenCourse {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getRegNo() {
|
||||
return regNo;
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setRegNo(int regNo) {
|
||||
this.regNo = regNo;
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public int getCourseId() {
|
||||
return courseId;
|
||||
public Course getCourse() {
|
||||
return course;
|
||||
}
|
||||
|
||||
public void setCourseId(int courseId) {
|
||||
this.courseId = courseId;
|
||||
public void setCourse(Course course) {
|
||||
this.course = course;
|
||||
}
|
||||
|
||||
public boolean isOwned() {
|
||||
|
@ -8,12 +8,13 @@ public class Token {
|
||||
@Id
|
||||
private int id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name ="Users")
|
||||
private int regNo;
|
||||
private User user;
|
||||
private String token;
|
||||
|
||||
public Token(int regNo, String token){
|
||||
this.regNo = regNo;
|
||||
public Token(User user, String token){
|
||||
this.user = user;
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
@ -21,13 +22,12 @@ public class Token {
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getRegNo() {
|
||||
return regNo;
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setRegNo(int regNo) {
|
||||
this.regNo = regNo;
|
||||
public void setUser(User regNo) {
|
||||
this.user = regNo;
|
||||
}
|
||||
|
||||
public String getToken(){
|
||||
|
@ -20,15 +20,17 @@ public class User {
|
||||
private String address;
|
||||
private String country;
|
||||
private Date birthDate;
|
||||
private String profilePictureUrl;
|
||||
private ovh.herisson.Clyde.Tables.Role role;
|
||||
private String password;
|
||||
public User(String lastName, String firstName, String email, String address, String country, Date birthDate, Role role, String password){
|
||||
public User(String lastName, String firstName, String email, String address, String country, Date birthDate, String profilePictureUrl, Role role, String password){
|
||||
this.lastName = lastName;
|
||||
this.firstName = firstName;
|
||||
this.email = email;
|
||||
this.address = address;
|
||||
this.country = country;
|
||||
this.birthDate = birthDate;
|
||||
this.profilePictureUrl = profilePictureUrl;
|
||||
this.role = role;
|
||||
this.password = password;
|
||||
}
|
||||
@ -86,6 +88,11 @@ public class User {
|
||||
this.birthDate = birthDate;
|
||||
}
|
||||
|
||||
public String getProfilePictureUrl(){return this.profilePictureUrl;}
|
||||
|
||||
public void setProfilePictureUrl(String profilePictureUrl){
|
||||
this.profilePictureUrl = profilePictureUrl;
|
||||
}
|
||||
public ovh.herisson.Clyde.Tables.Role getRole() {
|
||||
return role;
|
||||
}
|
||||
|
@ -7,15 +7,19 @@ public class UserCursus {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private int id;
|
||||
|
||||
//Un étudiant peut avoir plusieurs cursus
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "Users")
|
||||
private int regNo;
|
||||
private User user;
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "Cursus")
|
||||
private int cursusId;
|
||||
private Cursus cursus;
|
||||
|
||||
public UserCursus(int regNo, int cursusId){
|
||||
this.regNo = regNo;
|
||||
this.cursusId = cursusId;
|
||||
public UserCursus(User user, Cursus cursus){
|
||||
this.user = user;
|
||||
this.cursus = cursus;
|
||||
}
|
||||
|
||||
public UserCursus() {}
|
||||
@ -24,19 +28,19 @@ public class UserCursus {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getRegNo() {
|
||||
return regNo;
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setRegNo(int regNo) {
|
||||
this.regNo = regNo;
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public int getCursusId() {
|
||||
return cursusId;
|
||||
public Cursus getCursus() {
|
||||
return cursus;
|
||||
}
|
||||
|
||||
public void setCursusId(int cursusId) {
|
||||
this.cursusId = cursusId;
|
||||
public void setCursus(Cursus cursus) {
|
||||
this.cursus = cursus;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user
en vrai c'est un choix mais souvent il ne vaut mieux pas dire si le truc qui va pas c'est l'id ou le pass parce que avec ça tu peux savoir si qqun est inscrit sur le site ou non (ce qui n'est pas toujours souhaitable)
En gros si l'un des deux est mauvais tu retourne erreur d'authentication et puis basta x)
Mais certains sites font comme t'a fait donc c'est juste un choix. les deux sont bon pour moi