Skip to content

Commit

Permalink
Merge branch 'dev' into be/ErrorHandling
Browse files Browse the repository at this point in the history
  • Loading branch information
janniscloodt authored Dec 14, 2023
2 parents 9d44460 + ad4069a commit 232939e
Show file tree
Hide file tree
Showing 50 changed files with 1,825 additions and 14 deletions.
1 change: 1 addition & 0 deletions .idea/cloudworkMicromata.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/sqldialects.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added backend/.mvn/wrapper/maven-wrapper.jar
Binary file not shown.
34 changes: 34 additions & 0 deletions backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,40 @@
<artifactId>mockito-core</artifactId>
<version>5.8.0</version>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.3</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.12.3</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
<version>0.12.3</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.oskarwiedeweg.cloudwork;

import org.modelmapper.ModelMapper;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class BackendApplication {
Expand All @@ -10,4 +12,9 @@ public static void main(String[] args) {
SpringApplication.run(BackendApplication.class, args);
}

@Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.oskarwiedeweg.cloudwork.auth;

import com.oskarwiedeweg.cloudwork.user.UserService;
import lombok.Data;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Data
@Service
public class AppUserDetailsService implements UserDetailsService {

private final UserService userService;

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return new UserUserDetails(userService
.getUserByName(username)
.orElseThrow(() -> new UsernameNotFoundException("User with username '%s' not found!".formatted(username))));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.oskarwiedeweg.cloudwork.auth;

import com.oskarwiedeweg.cloudwork.auth.dto.AuthenticationDto;
import com.oskarwiedeweg.cloudwork.auth.dto.LoginDto;
import com.oskarwiedeweg.cloudwork.auth.dto.RegisterDto;
import jakarta.validation.Valid;
import lombok.Data;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

@Data
@RestController
@RequestMapping("/v1/auth")
public class AuthController {

private final AuthService authService;

@PostMapping("/login")
@ResponseStatus(HttpStatus.CREATED)
public AuthenticationDto login(@Valid @RequestBody LoginDto body) {
return authService.login(body);
}

@PostMapping("/register")
@ResponseStatus(HttpStatus.CREATED)
public AuthenticationDto register(@Valid @RequestBody RegisterDto body) {
return authService.register(body);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.oskarwiedeweg.cloudwork.auth;

import com.oskarwiedeweg.cloudwork.auth.dto.AuthenticationDto;
import com.oskarwiedeweg.cloudwork.auth.dto.LoginDto;
import com.oskarwiedeweg.cloudwork.auth.dto.RegisterDto;
import com.oskarwiedeweg.cloudwork.auth.token.TokenService;
import com.oskarwiedeweg.cloudwork.exception.DuplicateUserException;
import com.oskarwiedeweg.cloudwork.user.User;
import com.oskarwiedeweg.cloudwork.user.UserDto;
import com.oskarwiedeweg.cloudwork.user.UserService;
import lombok.Data;
import org.modelmapper.ModelMapper;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

@Data
@Service
public class AuthService {

private final AuthenticationManager authenticationManager;
private final TokenService tokenService;
private final ModelMapper modelMapper;
private final UserService userService;

public AuthenticationDto login(LoginDto loginDto) {
String username = transformUsername(loginDto.getUsername());
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, loginDto.getPassword());

Authentication authenticated;
try {
authenticated = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
} catch (BadCredentialsException e) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Bad credentials");
}

if (!(authenticated.getPrincipal() instanceof UserUserDetails userDetails)) {
throw new RuntimeException("User Details are not expected UserUserDetails!");
}

User user = userDetails.getUser();

String token = tokenService.generateToken(user);

return new AuthenticationDto(token, modelMapper.map(user, UserDto.class));
}

public AuthenticationDto register(RegisterDto body) {
String username = transformUsername(body.getUsername());


Long userId;
try {
userId = userService.createUser(username, body.getEmail(), body.getPassword());
} catch (DuplicateUserException e) {
throw new ResponseStatusException(HttpStatus.CONFLICT, "Duplicate username '%s'".formatted(username));
}

User tempUser = User.builder()
.id(userId)
.email(body.getEmail())
.name(username)
.build();
String token = tokenService.generateToken(tempUser);

return new AuthenticationDto(token, modelMapper.map(tempUser, UserDto.class));
}

private String transformUsername(String username) {
return username.toLowerCase();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.oskarwiedeweg.cloudwork.auth;

import com.oskarwiedeweg.cloudwork.user.User;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

@Data
public class UserUserDetails implements UserDetails {

private final User user;

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}

@Override
public String getPassword() {
return user.getPassword();
}

@Override
public String getUsername() {
return user.getName();
}

@Override
public boolean isAccountNonExpired() {
return true;
}

@Override
public boolean isAccountNonLocked() {
return true;
}

@Override
public boolean isCredentialsNonExpired() {
return true;
}

@Override
public boolean isEnabled() {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.oskarwiedeweg.cloudwork.auth.dto;

import com.oskarwiedeweg.cloudwork.user.UserDto;
import lombok.Data;

@Data
public class AuthenticationDto {

private final String accessToken;
private final UserDto userData;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.oskarwiedeweg.cloudwork.auth.dto;

import jakarta.validation.constraints.NotBlank;
import lombok.Data;

@Data
public class LoginDto {

@NotBlank
private final String username;

@NotBlank
private final String password;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.oskarwiedeweg.cloudwork.auth.dto;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import lombok.Data;

@Data
public class RegisterDto {

@NotBlank
@Pattern(regexp = "([A-Za-z0-9-._]{3,})")
private final String username;

@Email
@NotBlank
private final String email;

@NotBlank
@Pattern(regexp = "((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])).{8,}")
private final String password;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.oskarwiedeweg.cloudwork.auth.token;

import org.springframework.security.authentication.AbstractAuthenticationToken;

import java.util.Collections;

public class JwtAuthenticationToken extends AbstractAuthenticationToken {

private final Long userId;
private final String jwtToken;

public JwtAuthenticationToken(Long userId, String jwtToken) {
super(Collections.emptyList());
this.userId = userId;
this.jwtToken = jwtToken;
setAuthenticated(true);
}

@Override
public Object getCredentials() {
return jwtToken;
}

@Override
public Long getPrincipal() {
return userId;
}
}
Loading

0 comments on commit 232939e

Please sign in to comment.