Implements New AuthDTO and Refactors AuthService Implementation

This commit is contained in:
2023-08-22 01:05:21 -03:00
parent 68721381a6
commit 6dbd6452fe
9 changed files with 170 additions and 148 deletions

View File

@@ -0,0 +1,34 @@
package com.hideyoshi.backendportfolio.base.security.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.hideyoshi.backendportfolio.base.user.model.TokenDTO;
import com.hideyoshi.backendportfolio.base.user.model.UserDTO;
import lombok.Builder;
import lombok.Data;
import java.io.Serializable;
@Data
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class AuthDTO implements Serializable {
private UserDTO user;
private TokenDTO accessToken;
private TokenDTO refreshToken;
public AuthDTO(UserDTO user) {
this.user = user.toResponse();
}
public AuthDTO(UserDTO user, TokenDTO accessToken, TokenDTO refreshToken) {
this.user = user.toResponse();
this.accessToken = accessToken;
this.refreshToken = refreshToken;
}
}

View File

@@ -1,6 +1,7 @@
package com.hideyoshi.backendportfolio.base.security.service;
import com.auth0.jwt.algorithms.Algorithm;
import com.hideyoshi.backendportfolio.base.security.model.AuthDTO;
import com.hideyoshi.backendportfolio.base.user.model.TokenDTO;
import com.hideyoshi.backendportfolio.base.user.model.UserDTO;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -22,13 +23,13 @@ public interface AuthService {
UsernamePasswordAuthenticationToken verifyAccessToken(String authorizationHeader);
UserDTO refreshAccessToken(String refreshToken, HttpServletRequest request, HttpServletResponse response);
AuthDTO refreshAccessToken(String refreshToken, HttpServletRequest request, HttpServletResponse response);
UserDTO signupUser(@Valid UserDTO user, HttpServletRequest request);
AuthDTO signupUser(@Valid UserDTO user, HttpServletRequest request);
UserDTO generateUserWithTokens(UserDTO user, HttpServletRequest request);
AuthDTO generateUserWithTokens(UserDTO user, HttpServletRequest request);
UserDTO processOAuthPostLogin(@Valid UserDTO user, HttpServletRequest request);
AuthDTO processOAuthPostLogin(@Valid UserDTO user, HttpServletRequest request);
void loginUser(HttpServletRequest request, HttpServletResponse response, @Valid UserDTO user) throws IOException;

View File

@@ -5,6 +5,7 @@ import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hideyoshi.backendportfolio.base.security.model.AuthDTO;
import com.hideyoshi.backendportfolio.base.security.oauth.mapper.OAuthMap;
import com.hideyoshi.backendportfolio.base.security.oauth.mapper.OAuthMapper;
import com.hideyoshi.backendportfolio.base.user.entity.Provider;
@@ -112,7 +113,9 @@ public class AuthServiceImpl implements AuthService {
@Override
public UsernamePasswordAuthenticationToken verifyAccessToken(String authorizationHeader) {
if (authorizationHeader.startsWith(AUTHORIZATION_TYPE_STRING)) {
if (!authorizationHeader.startsWith(AUTHORIZATION_TYPE_STRING)) {
return null;
}
String authorizationToken = authorizationHeader.substring(AUTHORIZATION_TYPE_STRING.length());
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET.getBytes());
@@ -127,15 +130,71 @@ public class AuthServiceImpl implements AuthService {
stream(roles).forEach(role -> {
authorities.add(new SimpleGrantedAuthority(role));
});
return new UsernamePasswordAuthenticationToken(username, null, authorities);
}
return null;
}
@Override
public UserDTO refreshAccessToken(String refreshToken, HttpServletRequest request, HttpServletResponse response) {
public AuthDTO generateUserWithTokens(UserDTO user, HttpServletRequest request) {
if (Objects.nonNull(refreshToken)) {
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET.getBytes());
HashMap<String, TokenDTO> tokens = this.generateTokens(user, algorithm, request);
HttpSession httpSession = request.getSession();
AuthDTO authObject = new AuthDTO(user, tokens.get("accessToken"), tokens.get("refreshToken"));
httpSession.setAttribute("user", authObject);
return authObject;
}
@Override
public AuthDTO signupUser(@Valid UserDTO user, HttpServletRequest request) {
user.setProvider(Provider.LOCAL);
UserDTO authenticatedUser = this.userService.saveUser(user);
authenticatedUser.setProfilePictureUrl(
this.storageService.getFileUrl(authenticatedUser.getUsername(), "profile")
.getPresignedUrl()
);
return this.generateUserWithTokens(
authenticatedUser,
request
);
}
@Override
public void loginUser(HttpServletRequest request, HttpServletResponse response, @Valid UserDTO user) throws IOException {
user.setProfilePictureUrl(
this.storageService.getFileUrl(user.getUsername(), "profile")
.getPresignedUrl()
);
AuthDTO authObject = this.generateUserWithTokens(
user,
request
);
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper()
.writeValue(response.getOutputStream(), authObject);
}
@Override
public AuthDTO refreshAccessToken(String refreshToken, HttpServletRequest request, HttpServletResponse response) {
if (!Objects.nonNull(refreshToken)) {
resolver.resolveException(
request,
response,
null,
new BadRequestException("Invalid Refresh Token. Please authenticate first.")
);
}
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET.getBytes());
@@ -143,11 +202,14 @@ public class AuthServiceImpl implements AuthService {
DecodedJWT decodedJWT = verifier.verify(refreshToken);
UserDTO user = this.userService.getUser(decodedJWT.getSubject());
if (Objects.nonNull(user)) {
user.setProfilePictureUrl(
this.storageService.getFileUrl(user.getUsername(), "profile")
.getPresignedUrl()
);
HttpSession httpSession = request.getSession();
UserDTO authenticatedUser = user.toResponse(
AuthDTO authenticatedUser = new AuthDTO(
user,
this.generateAccessToken(user, algorithm, request),
new TokenDTO(
refreshToken,
@@ -156,74 +218,12 @@ public class AuthServiceImpl implements AuthService {
);
httpSession.setAttribute("user", authenticatedUser);
return authenticatedUser;
}
} else {
resolver.resolveException(
request,
response,
null,
new BadRequestException("Invalid Refresh Token. Please authenticate first.")
);
}
return null;
}
@Override
public UserDTO signupUser(@Valid UserDTO user, HttpServletRequest request) {
user.setProvider(Provider.LOCAL);
UserDTO authenticatedUser = this.generateUserWithTokens(
this.userService.saveUser(user),
request
);
authenticatedUser.setProfilePictureUrl(
this.storageService.getFileUrl(authenticatedUser.getUsername(), "profile")
.getPresignedUrl()
);
return authenticatedUser;
}
@Override
public void loginUser(HttpServletRequest request, HttpServletResponse response, @Valid UserDTO user) throws IOException {
UserDTO authenticatedUser = this.generateUserWithTokens(
user,
request
);
authenticatedUser.setProfilePictureUrl(
this.storageService.getFileUrl(authenticatedUser.getUsername(), "profile")
.getPresignedUrl()
);
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper()
.writeValue(response.getOutputStream(), authenticatedUser);
}
@Override
public UserDTO generateUserWithTokens(UserDTO user, HttpServletRequest request) {
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET.getBytes());
HashMap<String, TokenDTO> tokens = this.generateTokens(user, algorithm, request);
HttpSession httpSession = request.getSession();
UserDTO userAuthenticated = user.toResponse(tokens.get("accessToken"), tokens.get("refreshToken"));
httpSession.setAttribute("user", userAuthenticated);
return userAuthenticated;
}
@Override
public UserDTO processOAuthPostLogin(@Valid UserDTO user, HttpServletRequest request) {
public AuthDTO processOAuthPostLogin(@Valid UserDTO user, HttpServletRequest request) {
if (Objects.nonNull(user.getId())) {
this.userService.alterUser(user.getId(), user);
@@ -234,25 +234,49 @@ public class AuthServiceImpl implements AuthService {
return this.generateUserWithTokens(user, request);
}
@Override
public void loginOAuthUser(HttpServletRequest request,
HttpServletResponse response,
OAuth2User oauthUser) throws IOException {
String[] url = request.getRequestURL().toString().split("/");
String clientId = url[url.length-1];
String clientId = this.getClientFromUrl(request.getRequestURL().toString());
OAuthMap oauthMap = null;
try {
oauthMap = (OAuthMap) OAuthMapper.byValue(clientId).getMap()
.getDeclaredConstructor(OAuth2User.class).newInstance(oauthUser);
} catch (Exception e) {
throw new BadRequestException("No Such Provider");
OAuthMap oauthMap = this.generateOAuthMap(clientId, oauthUser);
AuthDTO authObject = this.processOAuthPostLogin(
this.generateUserFromAuthUser(oauthMap, oauthUser),
request
);
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper()
.writeValue(response.getOutputStream(), authObject);
}
@Override
public UserDTO getLoggedUser() {
String username = (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return userService.getUser(username);
}
private String getClientFromUrl(String url) {
String[] urlPartition = url.split("/");
return urlPartition[urlPartition.length - 1];
}
private OAuthMap generateOAuthMap(String clientId, OAuth2User oauthUser) {
try {
return (OAuthMap) OAuthMapper.byValue(clientId).getMap()
.getDeclaredConstructor(OAuth2User.class).newInstance(oauthUser);
} catch (Exception e) {
throw new BadRequestException("Unsupported OAuth Client.");
}
}
private UserDTO generateUserFromAuthUser(OAuthMap oauthMap, OAuth2User oauthUser) {
UserDTO user = null;
try {
user = this.userService.getUser(oauthMap.getPrincipal());
user.setProfilePictureUrl(oauthMap.getProfilePicture());
} catch (BadRequestException e) {
user = UserDTO.builder()
.name(oauthUser.getAttribute("name"))
@@ -260,24 +284,11 @@ public class AuthServiceImpl implements AuthService {
.email(oauthUser.getAttribute("email"))
.roles(Arrays.asList(Role.USER))
.provider(oauthMap.getProvider())
.profilePictureUrl(oauthMap.getProfilePicture())
.build();
}
user.setProfilePictureUrl(oauthMap.getProfilePicture());
UserDTO authenticatedUser = this.processOAuthPostLogin(
user,
request
);
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper()
.writeValue(response.getOutputStream(), authenticatedUser);
}
public UserDTO getLoggedUser() {
String username = (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return userService.getUser(username);
return user;
}
}

View File

@@ -1,5 +1,6 @@
package com.hideyoshi.backendportfolio.base.session.api;
import com.hideyoshi.backendportfolio.base.security.model.AuthDTO;
import com.hideyoshi.backendportfolio.base.session.service.SessionManagerService;
import com.hideyoshi.backendportfolio.base.user.model.UserDTO;
import lombok.RequiredArgsConstructor;
@@ -19,7 +20,7 @@ public class SessionController {
private final SessionManagerService sessionManagerService;
@GetMapping(path = "/validate")
public ResponseEntity<UserDTO> validateCurrentSession(HttpSession session) {
public ResponseEntity<AuthDTO> validateCurrentSession(HttpSession session) {
return ResponseEntity.ok(this.sessionManagerService.validateSession(session));
}

View File

@@ -1,12 +1,12 @@
package com.hideyoshi.backendportfolio.base.session.service;
import com.hideyoshi.backendportfolio.base.user.model.UserDTO;
import com.hideyoshi.backendportfolio.base.security.model.AuthDTO;
import javax.servlet.http.HttpSession;
public interface SessionManagerService {
UserDTO validateSession(HttpSession session);
AuthDTO validateSession(HttpSession session);
void destroySession(HttpSession session);

View File

@@ -1,32 +1,19 @@
package com.hideyoshi.backendportfolio.base.session.service;
import com.hideyoshi.backendportfolio.base.user.model.UserDTO;
import com.hideyoshi.backendportfolio.base.security.model.AuthDTO;
import com.hideyoshi.backendportfolio.base.user.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpSession;
import java.util.Objects;
@Service
@RequiredArgsConstructor
public class SessionManagerServiceImpl implements SessionManagerService {
private final UserService userService;
@Override
public UserDTO validateSession(HttpSession session) {
UserDTO sessionObject = (UserDTO) session.getAttribute("user");
if (Objects.nonNull(sessionObject)) {
sessionObject = sessionObject.toResponse(
sessionObject.getAccessToken(),
sessionObject.getRefreshToken()
);
}
return sessionObject;
public AuthDTO validateSession(HttpSession session) {
return (AuthDTO) session.getAttribute("user");
}
@Override

View File

@@ -1,5 +1,6 @@
package com.hideyoshi.backendportfolio.base.user.api;
import com.hideyoshi.backendportfolio.base.security.model.AuthDTO;
import com.hideyoshi.backendportfolio.base.security.service.AuthService;
import com.hideyoshi.backendportfolio.base.user.model.TokenDTO;
import com.hideyoshi.backendportfolio.base.user.model.UserDTO;
@@ -45,7 +46,7 @@ public class UserController {
@PostMapping("/signup")
@UserResourceGuard(accessType = UserResourceGuardEnum.OPEN)
public ResponseEntity<UserDTO> signupUser(@RequestBody @Valid UserDTO user, HttpServletRequest request) {
public ResponseEntity<AuthDTO> signupUser(@RequestBody @Valid UserDTO user, HttpServletRequest request) {
URI uri = URI.create(
ServletUriComponentsBuilder
.fromCurrentContextPath()
@@ -56,7 +57,7 @@ public class UserController {
@PostMapping("/login/refresh")
@UserResourceGuard(accessType = UserResourceGuardEnum.OPEN)
public ResponseEntity<UserDTO> refreshAccessToken(
public ResponseEntity<AuthDTO> refreshAccessToken(
@RequestBody @Valid TokenDTO refreshToken,
HttpServletRequest request,
HttpServletResponse response) {

View File

@@ -1,6 +1,8 @@
package com.hideyoshi.backendportfolio.base.user.model;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.*;
import javax.validation.constraints.NotNull;
@@ -10,6 +12,8 @@ import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class TokenDTO implements Serializable {
@NotNull(message = "Invalid AccessToken. Please Authenticate first.")

View File

@@ -55,10 +55,6 @@ public class UserDTO implements UserDetails {
private String profilePictureUrl;
private TokenDTO accessToken;
private TokenDTO refreshToken;
private Provider provider;
public UserDTO(User entity) {
@@ -118,26 +114,13 @@ public class UserDTO implements UserDetails {
}
public UserDTO toResponse() {
return UserDTO.builder()
.name(this.name)
.email(this.email)
.username(this.username)
.provider(this.provider)
.profilePictureUrl(this.profilePictureUrl)
.build();
}
public UserDTO toResponse(TokenDTO accessToken, TokenDTO refreshToken) {
return UserDTO.builder()
.id(this.id)
.name(this.name)
.email(this.email)
.username(this.username)
.provider(this.provider)
.roles(this.roles)
.profilePictureUrl(this.profilePictureUrl)
.accessToken(accessToken)
.refreshToken(refreshToken)
.build();
}