Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented Jwt and Oauth2.0 Authentication #67

Merged
merged 9 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 36 additions & 11 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.3</version>
<relativePath/> <!-- lookup parent from repository -->
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com</groupId>
<artifactId>libraryman-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>libraryman-api</name>
<description>Revolutionize book management with LibraryMan! Easily track stock, borrowers, and due dates, streamlining operations for schools, companies, and libraries worldwide, ensuring efficient and organized book lending.</description>
<url/>
<description>Revolutionize book management with LibraryMan! Easily track
stock, borrowers, and due dates, streamlining operations for schools,
companies, and libraries worldwide, ensuring efficient and organized
book lending.</description>
<url />
<licenses>
<license/>
<license />
</licenses>
<developers>
<developer/>
<developer />
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
<connection />
<developerConnection />
<tag />
<url />
</scm>
<properties>
<java.version>17</java.version>
Expand All @@ -50,7 +54,23 @@
<scope>runtime</scope>
<optional>true</optional>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>com.mysql</groupId>
Expand Down Expand Up @@ -80,6 +100,11 @@
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>

</dependency>

</dependencies>

Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/libraryman_api/book/BookController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.libraryman_api.exception.ResourceNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.List;
Expand Down Expand Up @@ -51,6 +52,7 @@ public ResponseEntity<Book> getBookById(@PathVariable int id) {
* @return the added {@link Book} object.
*/
@PostMapping
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')")
public Book addBook(@RequestBody Book book) {
return bookService.addBook(book);
}
Expand All @@ -63,6 +65,7 @@ public Book addBook(@RequestBody Book book) {
* @return the updated {@link Book} object.
*/
@PutMapping("/{id}")
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')")
public Book updateBook(@PathVariable int id, @RequestBody Book bookDetails) {
return bookService.updateBook(id, bookDetails);
}
Expand All @@ -73,6 +76,7 @@ public Book updateBook(@PathVariable int id, @RequestBody Book bookDetails) {
* @param id the ID of the book to delete.
*/
@DeleteMapping("/{id}")
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')")
public void deleteBook(@PathVariable int id) {
bookService.deleteBook(id);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.libraryman_api.borrowing;

import com.libraryman_api.exception.ResourceNotFoundException;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.List;
Expand Down Expand Up @@ -31,6 +33,7 @@ public BorrowingController(BorrowingService borrowingService) {
* @return a list of {@link Borrowings} objects representing all borrowings.
*/
@GetMapping
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')")
public List<Borrowings> getAllBorrowings() {
return borrowingService.getAllBorrowings();
}
Expand Down Expand Up @@ -75,6 +78,7 @@ public String payFine(@PathVariable int id) {
* @return a list of {@link Borrowings} objects representing the member's borrowings.
*/
@GetMapping("member/{memberId}")
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')")
public List<Borrowings> getAllBorrowingsOfAMember(@PathVariable int memberId) {
return borrowingService.getAllBorrowingsOfMember(memberId);
}
Expand All @@ -87,6 +91,7 @@ public List<Borrowings> getAllBorrowingsOfAMember(@PathVariable int memberId) {
* @throws ResourceNotFoundException if the borrowing record with the specified ID is not found.
*/
@GetMapping("{borrowingId}")
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')")
public Borrowings getBorrowingById(@PathVariable int borrowingId) {
return borrowingService.getBorrowingById(borrowingId)
.orElseThrow(() -> new ResourceNotFoundException("Borrowing not found"));
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/libraryman_api/member/MemberController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.libraryman_api.exception.ResourceNotFoundException;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.List;
Expand Down Expand Up @@ -31,6 +32,7 @@ public MemberController(MemberService memberService) {
* @return a list of {@link Members} representing all members in the library
*/
@GetMapping
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')")
public List<Members> getAllMembers() {
return memberService.getAllMembers();
}
Expand All @@ -43,6 +45,7 @@ public List<Members> getAllMembers() {
* @return a {@link ResponseEntity} containing the found {@link Members} object
*/
@GetMapping("/{id}")
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')")
public ResponseEntity<Members> getMemberById(@PathVariable int id) {
return memberService.getMemberById(id)
.map(ResponseEntity::ok)
Expand Down Expand Up @@ -80,6 +83,7 @@ public Members updateMember(@PathVariable int id, @RequestBody Members memberDet
* @param id the ID of the member to delete
*/
@DeleteMapping("/{id}")
@PreAuthorize("hasRole('LIBRARIAN') or hasRole('ADMIN')")
public void deleteMember(@PathVariable int id) {
memberService.deleteMember(id);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public interface MemberRepository extends JpaRepository<Members, Integer> {

Optional<Members> findByMemberId(int memberId);

Optional<Members> findByUsername(String username);

/**
* SELECT SUM(amount) AS totalFines
Expand Down
27 changes: 26 additions & 1 deletion src/main/java/com/libraryman_api/member/Members.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@

import jakarta.persistence.*;

import java.util.Collection;
import java.util.Collections;
import java.util.Date;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;


@Entity
public class Members {
public class Members implements UserDetails{

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
Expand All @@ -20,6 +26,9 @@ public class Members {
@Column(nullable = false)
private String name;

@Column(name = "username")
private String username;

@Column(unique = true, nullable = false)
private String email;

Expand All @@ -33,6 +42,7 @@ public class Members {
@Column(name = "membership_date")
private Date membershipDate;




public Members() {
Expand Down Expand Up @@ -89,4 +99,19 @@ public Date getMembershipDate() {
public void setMembershipDate(Date membershipDate) {
this.membershipDate = membershipDate;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// TODO Auto-generated method stub
return Collections.singletonList(new SimpleGrantedAuthority("ROLE_"+role.name()));
}

}
20 changes: 0 additions & 20 deletions src/main/java/com/libraryman_api/security/LoginController.java

This file was deleted.

This file was deleted.

33 changes: 0 additions & 33 deletions src/main/java/com/libraryman_api/security/WebConfiguration.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.libraryman_api.security;
package com.libraryman_api.security.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.libraryman_api.security.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import com.libraryman_api.security.jwt.JwtAuthenticationFilter;

import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS;

@Configuration
@EnableWebSecurity(debug = true) // Do not use (debug=true) in a production system! as this contain sensitive information.
@EnableMethodSecurity(prePostEnabled = true)
public class WebConfiguration {

private JwtAuthenticationFilter jwtFilter;

public WebConfiguration(JwtAuthenticationFilter jwtFilter) {
this.jwtFilter=jwtFilter;
}
@Bean
public SecurityFilterChain web(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests((request) -> request
// make sure it is in order to access the proper Url

.requestMatchers("/api/signup").permitAll()
.requestMatchers("/api/login").permitAll()
.requestMatchers("/api/logout").permitAll()
.anyRequest().authenticated()
)
.logout(logout->logout
.deleteCookies("LibraryManCookie"))
.sessionManagement(session -> session.sessionCreationPolicy(STATELESS))
.formLogin(withDefaults());

http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
.httpBasic(httpBasic -> {});

http.oauth2Login(withDefaults());
return http.build();
}

@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration builder) throws Exception {
return builder.getAuthenticationManager();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowCredentials(true);
corsConfiguration.addAllowedOriginPattern("*");
corsConfiguration.addAllowedHeader("Authorization");
corsConfiguration.addAllowedHeader("Content-Type");
corsConfiguration.addAllowedHeader("Accept");
corsConfiguration.addAllowedMethod("POST");
corsConfiguration.addAllowedMethod("PUT");
corsConfiguration.addAllowedMethod("GET");
corsConfiguration.addAllowedMethod("DELETE");
corsConfiguration.addAllowedMethod("OPTIONS");
corsConfiguration.setMaxAge(3600L);

source.registerCorsConfiguration("/**", corsConfiguration);
return source;
}

@Bean
public CorsFilter corsFilter() {
return new CorsFilter(corsConfigurationSource());
}

}
Loading