1
0
forked from PGL/Clyde

Merge pull request 'Max/Backend/loginApi Ajout mock Users et Tokens' (#62) from Max/Backend/loginApi into master

Reviewed-on: PGL/Clyde#62
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
Reviewed-by: Wal <karpinskiwal@gmail.com>
Reviewed-by: LeoMoulin <leomoulin125@gmail.com>
This commit is contained in:
Maxime 2024-03-08 16:50:22 +01:00
commit 875cfb8b7c
18 changed files with 334 additions and 73 deletions

View File

@ -21,6 +21,7 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-mail") implementation("org.springframework.boot:spring-boot-starter-mail")
implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-jpa") 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("com.kohlschutter.junixsocket:junixsocket-core:2.9.0")
// implementation("org.springframework.session:spring-session-jdbc") // implementation("org.springframework.session:spring-session-jdbc")
developmentOnly("org.springframework.boot:spring-boot-devtools") developmentOnly("org.springframework.boot:spring-boot-devtools")

View File

@ -2,8 +2,9 @@ package ovh.herisson.Clyde;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
@SpringBootApplication @SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
public class ClydeApplication { public class ClydeApplication {
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -2,10 +2,12 @@ package ovh.herisson.Clyde.EndPoints;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; 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; import ovh.herisson.Clyde.Tables.User;
@ -13,30 +15,31 @@ import ovh.herisson.Clyde.Tables.User;
@CrossOrigin(origins = "http://localhost:5173") @CrossOrigin(origins = "http://localhost:5173")
public class UserController { public class UserController {
private final UserRepository userRepo; private final UserService userService;
private final AuthenticatorService authServ;
public UserController(UserRepository userRepo){ public UserController(UserService userService, AuthenticatorService authServ){
this.userRepo = userRepo; this.userService = userService;
this.authServ = authServ;
} }
@GetMapping("/user") @GetMapping("/user")
public ResponseEntity<User> getUsers(@RequestHeader("Authorization") String token){ public ResponseEntity<User> getUser(@RequestHeader("Authorization") String token){
//TODO User user = authServ.getUserFromToken(token);
// Get the token thru the data base if (user == null) {
// tokenRepo.findToken(token) => User userFromToken return new UnauthorizedResponse<>(null);
// si role != secretary => return error : ResponseEntity<User>(null, HttpStatus.UNAUTHORIZED) }
return new ResponseEntity<User>(/**userRepo.findById(userFromToken.id),**/ HttpStatus.OK); return new ResponseEntity<>(user, HttpStatus.OK);
} }
@PostMapping("/user") @PostMapping("/user")
public ResponseEntity<String> postUser(@RequestBody User 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); return new ResponseEntity<String>(String.format("Account created with ID:%s",user.getRegNo()),HttpStatus.CREATED);
} }
@GetMapping("/users") @GetMapping("/users")
public Iterable<User> getAllUsers(){//TODO ne l'accepter que si c'est le secrétariat public Iterable<User> getAllUsers(){
return userRepo.findAll(); return userService.getAll();
} }

View File

@ -6,8 +6,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration @Configuration
public class JdbcConfig { public class JdbcConfig {

View File

@ -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);
}

View File

@ -10,6 +10,8 @@ public interface UserRepository extends CrudRepository<User, Long> {
User findById(long id); User findById(long id);
User findByEmail(String email);
/** /**
@Query(value = "select a.* from Users a ",nativeQuery = true) @Query(value = "select a.* from Users a ",nativeQuery = true)
Iterable<User> findAllUsers();**/ Iterable<User> findAllUsers();**/

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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));
}
}

View File

@ -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();
}
}

View File

@ -8,15 +8,17 @@ public class CursusCourse {
@GeneratedValue(strategy = GenerationType.AUTO) @GeneratedValue(strategy = GenerationType.AUTO)
private int id; private int id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "Cursus") @JoinColumn(name = "Cursus")
private int cursusId; private Cursus cursus;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "Course") @JoinColumn(name = "Course")
private int courseId; private Course course;
public CursusCourse(int cursusId, int courseId){ public CursusCourse(Cursus cursus, Course course){
this.cursusId = cursusId; this.cursus = cursus;
this.courseId = courseId; this.course = course;
} }
public CursusCourse() {} public CursusCourse() {}
@ -25,19 +27,19 @@ public class CursusCourse {
return id; return id;
} }
public int getCourseId() { public Course getCourse() {
return courseId; return course;
} }
public void setCourseId(int courseId){ public void setCourse(Course course){
this.courseId = courseId; this.course = course;
} }
public int getCursusId() { public Cursus getCursus() {
return cursusId; return cursus;
} }
public void setCursusId(int cursusId) { public void setCursus(Cursus cursus) {
this.cursusId = cursusId; this.cursus = cursus;
} }
} }

View File

@ -8,12 +8,13 @@ public class Secretary {
@GeneratedValue(strategy = GenerationType.AUTO) @GeneratedValue(strategy = GenerationType.AUTO)
private int id; private int id;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "Users") @JoinColumn(name = "Users")
private int regNo; private User user;
private String faculty; private String faculty;
public Secretary(int regNo, String faculty){ public Secretary(User user, String faculty){
this.regNo = regNo; this.user = user;
this.faculty = faculty; this.faculty = faculty;
} }
@ -23,12 +24,12 @@ public class Secretary {
return id; return id;
} }
public int getRegNo() { public User getUser() {
return regNo; return user;
} }
public void setRegNo(int regNo) { public void setUser(User user) {
this.regNo = regNo; this.user = user;
} }
public String getFaculty() { public String getFaculty() {

View File

@ -8,18 +8,21 @@ public class TeacherGivenCourse {
@GeneratedValue(strategy = GenerationType.AUTO) @GeneratedValue(strategy = GenerationType.AUTO)
private int id; private int id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "Users") @JoinColumn(name = "Users")
private int regNo; private User user;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "Course") @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) //This flag helps make the difference between an assistant or a Teacher (who owns the course)
private boolean owned; private boolean owned;
public TeacherGivenCourse(int regNo, int courseId, boolean owned){ public TeacherGivenCourse(User user, Course course, boolean owned){
this.regNo = regNo; this.user = user;
this.courseId = courseId; this.course = course;
this.owned = owned; this.owned = owned;
} }
@ -29,20 +32,20 @@ public class TeacherGivenCourse {
return id; return id;
} }
public int getRegNo() { public User getUser() {
return regNo; return user;
} }
public void setRegNo(int regNo) { public void setUser(User user) {
this.regNo = regNo; this.user = user;
} }
public int getCourseId() { public Course getCourse() {
return courseId; return course;
} }
public void setCourseId(int courseId) { public void setCourse(Course course) {
this.courseId = courseId; this.course = course;
} }
public boolean isOwned() { public boolean isOwned() {

View File

@ -8,12 +8,13 @@ public class Token {
@Id @Id
private int id; private int id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name ="Users") @JoinColumn(name ="Users")
private int regNo; private User user;
private String token; private String token;
public Token(int regNo, String token){ public Token(User user, String token){
this.regNo = regNo; this.user = user;
this.token = token; this.token = token;
} }
@ -21,13 +22,12 @@ public class Token {
public int getId() { public int getId() {
return id; return id;
} }
public User getUser() {
public int getRegNo() { return user;
return regNo;
} }
public void setRegNo(int regNo) { public void setUser(User regNo) {
this.regNo = regNo; this.user = regNo;
} }
public String getToken(){ public String getToken(){

View File

@ -20,15 +20,17 @@ public class User {
private String address; private String address;
private String country; private String country;
private Date birthDate; private Date birthDate;
private String profilePictureUrl;
private ovh.herisson.Clyde.Tables.Role role; private ovh.herisson.Clyde.Tables.Role role;
private String password; 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.lastName = lastName;
this.firstName = firstName; this.firstName = firstName;
this.email = email; this.email = email;
this.address = address; this.address = address;
this.country = country; this.country = country;
this.birthDate = birthDate; this.birthDate = birthDate;
this.profilePictureUrl = profilePictureUrl;
this.role = role; this.role = role;
this.password = password; this.password = password;
} }
@ -86,6 +88,11 @@ public class User {
this.birthDate = birthDate; this.birthDate = birthDate;
} }
public String getProfilePictureUrl(){return this.profilePictureUrl;}
public void setProfilePictureUrl(String profilePictureUrl){
this.profilePictureUrl = profilePictureUrl;
}
public ovh.herisson.Clyde.Tables.Role getRole() { public ovh.herisson.Clyde.Tables.Role getRole() {
return role; return role;
} }

View File

@ -7,15 +7,19 @@ public class UserCursus {
@Id @Id
@GeneratedValue(strategy = GenerationType.AUTO) @GeneratedValue(strategy = GenerationType.AUTO)
private int id; private int id;
//Un étudiant peut avoir plusieurs cursus
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "Users") @JoinColumn(name = "Users")
private int regNo; private User user;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "Cursus") @JoinColumn(name = "Cursus")
private int cursusId; private Cursus cursus;
public UserCursus(int regNo, int cursusId){ public UserCursus(User user, Cursus cursus){
this.regNo = regNo; this.user = user;
this.cursusId = cursusId; this.cursus = cursus;
} }
public UserCursus() {} public UserCursus() {}
@ -24,19 +28,19 @@ public class UserCursus {
return id; return id;
} }
public int getRegNo() { public User getUser() {
return regNo; return user;
} }
public void setRegNo(int regNo) { public void setUser(User user) {
this.regNo = regNo; this.user = user;
} }
public int getCursusId() { public Cursus getCursus() {
return cursusId; return cursus;
} }
public void setCursusId(int cursusId) { public void setCursus(Cursus cursus) {
this.cursusId = cursusId; this.cursus = cursus;
} }
} }