generated from Arquisoft/wiq_0
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from Arquisoft/feat/spring-api
Added JWT authentication with Spring Security 3.2.2
- Loading branch information
Showing
23 changed files
with
798 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
node_modules | ||
coverage | ||
docs/build | ||
docs/build | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
api/src/main/java/lab/en2b/quizapi/auth/AuthController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package lab.en2b.quizapi.auth; | ||
|
||
import jakarta.validation.Valid; | ||
import lab.en2b.quizapi.auth.dtos.LoginDto; | ||
import lab.en2b.quizapi.auth.dtos.RefreshTokenDto; | ||
import lab.en2b.quizapi.auth.dtos.RegisterDto; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
@RestController | ||
@RequestMapping("/auth") | ||
public class AuthController { | ||
|
||
@Autowired | ||
private AuthService authService; | ||
|
||
@PostMapping("/register") | ||
public ResponseEntity<?> registerUser(@Valid @RequestBody RegisterDto registerRequest){ | ||
return authService.register(registerRequest); | ||
} | ||
|
||
@PostMapping("/login") | ||
public ResponseEntity<?> loginUser(@Valid @RequestBody LoginDto loginRequest){ | ||
return authService.login(loginRequest); | ||
} | ||
|
||
@PostMapping("/refresh-token") | ||
public ResponseEntity<?> refreshToken(@Valid @RequestBody RefreshTokenDto refreshTokenRequest){ | ||
return authService.refreshToken(refreshTokenRequest); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package lab.en2b.quizapi.auth; | ||
|
||
import lab.en2b.quizapi.auth.config.UserDetailsImpl; | ||
import lab.en2b.quizapi.auth.dtos.*; | ||
import lab.en2b.quizapi.auth.jwt.JwtUtils; | ||
import lab.en2b.quizapi.commons.exceptions.TokenRefreshException; | ||
import lab.en2b.quizapi.auth.dtos.RefreshTokenResponseDto; | ||
import lab.en2b.quizapi.commons.user.User; | ||
import lab.en2b.quizapi.commons.user.UserService; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.security.authentication.AuthenticationManager; | ||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.security.core.context.SecurityContextHolder; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.util.Set; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class AuthService { | ||
private final JwtUtils jwtUtils; | ||
private final AuthenticationManager authenticationManager; | ||
private final UserService userService; | ||
/** | ||
* Creates a session for a user. Throws an 401 unauthorized exception otherwise | ||
* @param loginRequest the request containing the login info | ||
* @return a response containing a fresh jwt token and a refresh token | ||
*/ | ||
@Transactional | ||
public ResponseEntity<JwtResponseDto> login(LoginDto loginRequest){ | ||
Authentication authentication = authenticationManager.authenticate( | ||
new UsernamePasswordAuthenticationToken(loginRequest.getEmail(), loginRequest.getPassword())); | ||
SecurityContextHolder.getContext().setAuthentication(authentication); | ||
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal(); | ||
|
||
return ResponseEntity.ok(new JwtResponseDto( | ||
jwtUtils.generateJwtTokenUserPassword(authentication), | ||
userService.assignNewRefreshToken(userDetails.getId()), | ||
userDetails.getId(), | ||
userDetails.getUsername(), | ||
userDetails.getEmail(), | ||
userDetails.getStringRoles()) | ||
); | ||
} | ||
|
||
public ResponseEntity<?> register(RegisterDto registerRequest) { | ||
userService.createUser(registerRequest,Set.of("user")); | ||
return ResponseEntity.ok("User registered successfully!"); | ||
} | ||
|
||
public ResponseEntity<?> refreshToken(RefreshTokenDto refreshTokenRequest) { | ||
User user = userService.findByRefreshToken(refreshTokenRequest.getRefreshToken()).orElseThrow(() -> new TokenRefreshException( | ||
"Refresh token is not in database!")); | ||
return ResponseEntity.ok(new RefreshTokenResponseDto(jwtUtils.generateTokenFromEmail(user.getEmail()), user.obtainRefreshIfValid())); | ||
} | ||
} |
84 changes: 84 additions & 0 deletions
84
api/src/main/java/lab/en2b/quizapi/auth/config/SecurityConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package lab.en2b.quizapi.auth.config; | ||
|
||
import lab.en2b.quizapi.auth.jwt.JwtAuthFilter; | ||
import lab.en2b.quizapi.commons.user.UserService; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.http.HttpMethod; | ||
import org.springframework.security.authentication.AuthenticationManager; | ||
import org.springframework.security.config.Customizer; | ||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; | ||
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.config.http.SessionCreationPolicy; | ||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | ||
import org.springframework.security.crypto.password.PasswordEncoder; | ||
import org.springframework.security.web.SecurityFilterChain; | ||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; | ||
import org.springframework.web.cors.CorsConfiguration; | ||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; | ||
import org.springframework.web.filter.CorsFilter; | ||
|
||
@Configuration | ||
@EnableWebSecurity | ||
@RequiredArgsConstructor | ||
public class SecurityConfig { | ||
@Autowired | ||
public UserService userService; | ||
@Bean | ||
public JwtAuthFilter authenticationJwtTokenFilter() { | ||
return new JwtAuthFilter(); | ||
} | ||
@Bean | ||
public PasswordEncoder passwordEncoder() { | ||
return new BCryptPasswordEncoder(); | ||
} | ||
@Bean | ||
public CorsFilter corsFilter() { | ||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); | ||
CorsConfiguration config = new CorsConfiguration(); | ||
// Configure CORS settings here | ||
config.setAllowCredentials(true); | ||
config.addAllowedOrigin("*"); | ||
config.addAllowedHeader("*"); | ||
config.addAllowedMethod("*"); | ||
source.registerCorsConfiguration("/**", config); | ||
return new CorsFilter(source); | ||
} | ||
/** | ||
* Security filter used for filtering all petitions, applying cors and asking for authentication among other things | ||
* @param http the http request to filter | ||
* @return the filtered request | ||
* @throws Exception if any problem happens when filtering | ||
*/ | ||
@Bean | ||
public SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception { | ||
return http | ||
.cors(Customizer.withDefaults()) | ||
.sessionManagement(configuration -> configuration.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) | ||
.authorizeHttpRequests(authorize -> authorize | ||
.requestMatchers(HttpMethod.POST,"/auth/**").permitAll() | ||
.anyRequest().authenticated()) | ||
.csrf(AbstractHttpConfigurer::disable) | ||
.authenticationManager(authenticationManager) | ||
.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class) | ||
.build(); | ||
//TODO: add exception handling | ||
} | ||
|
||
/** | ||
* Builds the authorization manager taking into account password encoding | ||
* @param http the http request to secure | ||
* @return the newly created authentication manager | ||
* @throws Exception if something goes wrong when creating the manager | ||
*/ | ||
@Bean | ||
public AuthenticationManager authManager(HttpSecurity http) throws Exception { | ||
AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class); | ||
authenticationManagerBuilder.userDetailsService(userService).passwordEncoder(passwordEncoder()); | ||
return authenticationManagerBuilder.build(); | ||
} | ||
} |
66 changes: 66 additions & 0 deletions
66
api/src/main/java/lab/en2b/quizapi/auth/config/UserDetailsImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package lab.en2b.quizapi.auth.config; | ||
|
||
import com.fasterxml.jackson.annotation.JsonIgnore; | ||
import lab.en2b.quizapi.commons.user.User; | ||
import lab.en2b.quizapi.commons.user.role.Role; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import org.springframework.security.core.GrantedAuthority; | ||
import org.springframework.security.core.authority.SimpleGrantedAuthority; | ||
import org.springframework.security.core.userdetails.UserDetails; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.stream.Collectors; | ||
|
||
@Getter | ||
@AllArgsConstructor | ||
public class UserDetailsImpl implements UserDetails { | ||
private Long id; | ||
private String username; | ||
private String email; | ||
@JsonIgnore | ||
private String password; | ||
private Collection<? extends GrantedAuthority> authorities; | ||
public static UserDetailsImpl build(User user) { | ||
List<GrantedAuthority> authorities = new ArrayList<>(); | ||
for(Role role : user.getRoles()){ | ||
authorities.add(new SimpleGrantedAuthority(role.getName())); | ||
} | ||
return new UserDetailsImpl(user.getId(),user.getUsername() , user.getEmail(), user.getPassword(), authorities); | ||
} | ||
|
||
@Override | ||
public boolean isAccountNonExpired() { | ||
return true; | ||
} | ||
@Override | ||
public boolean isAccountNonLocked() { | ||
return true; | ||
} | ||
@Override | ||
public boolean isCredentialsNonExpired() { | ||
return true; | ||
} | ||
@Override | ||
public boolean isEnabled() { | ||
return true; | ||
} | ||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) | ||
return true; | ||
if (o == null || getClass() != o.getClass()) | ||
return false; | ||
UserDetailsImpl user = (UserDetailsImpl) o; | ||
return Objects.equals(id, user.id); | ||
} | ||
|
||
public List<String> getStringRoles() { | ||
return getAuthorities().stream() | ||
.map(GrantedAuthority::getAuthority) | ||
.collect(Collectors.toList()); | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
api/src/main/java/lab/en2b/quizapi/auth/dtos/JwtResponseDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package lab.en2b.quizapi.auth.dtos; | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
import java.util.List; | ||
|
||
@AllArgsConstructor | ||
@NoArgsConstructor | ||
@Getter | ||
public class JwtResponseDto { | ||
private String token; | ||
@JsonProperty("refresh_token") | ||
private String refreshToken; | ||
@JsonProperty("user_id") | ||
private Long userId; | ||
private String username; | ||
private String email; | ||
private List<String> roles; | ||
} |
16 changes: 16 additions & 0 deletions
16
api/src/main/java/lab/en2b/quizapi/auth/dtos/LoginDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package lab.en2b.quizapi.auth.dtos; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Data; | ||
import lombok.NoArgsConstructor; | ||
import lombok.NonNull; | ||
|
||
@NoArgsConstructor | ||
@AllArgsConstructor | ||
@Data | ||
public class LoginDto { | ||
@NonNull | ||
private String email; | ||
@NonNull | ||
private String password; | ||
} |
16 changes: 16 additions & 0 deletions
16
api/src/main/java/lab/en2b/quizapi/auth/dtos/RefreshTokenDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package lab.en2b.quizapi.auth.dtos; | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Data; | ||
import lombok.NoArgsConstructor; | ||
import lombok.NonNull; | ||
|
||
@AllArgsConstructor | ||
@NoArgsConstructor | ||
@Data | ||
public class RefreshTokenDto { | ||
@NonNull | ||
@JsonProperty("refresh_token") | ||
private String refreshToken; | ||
} |
20 changes: 20 additions & 0 deletions
20
api/src/main/java/lab/en2b/quizapi/auth/dtos/RefreshTokenResponseDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package lab.en2b.quizapi.auth.dtos; | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import lombok.Getter; | ||
import lombok.Setter; | ||
|
||
@Getter | ||
@Setter | ||
public class RefreshTokenResponseDto { | ||
|
||
private String token; | ||
@JsonProperty("refresh_token") | ||
private String refreshToken; | ||
|
||
public RefreshTokenResponseDto(String accessToken, String refreshToken) { | ||
this.token = accessToken; | ||
this.refreshToken = refreshToken; | ||
} | ||
|
||
} |
Oops, something went wrong.