I am new to spring boot here. I have three micro-services one for user registration(authentication) and login(authorization) and two other services that requires authorization from the first.
Currently, the first microservice serves as the authentication and authorization point as no user can access the other two services without having passed through the first one.
Apparently, I retrieve the request header in the other two services to be able to get unique user details from the database and return unique resources.
@PostMapping("/clients")
public ResponseEntity<ResponseModel> addClient(@Valid @RequestBody Client client, @RequestHeader("Authorization") String auth) {
ClientRequest clientCreated = clientService.addClient(client, auth);
return handleSuccessResponseEntity("Client added successfully", HttpStatus.CREATED, clientCreated);
}
And also have authentication filter and authentication entry point to authenticate request in all the three services. I am not sure if this is a good implementation.
@Component
@Slf4j
public class JwtFilter extends OncePerRequestFilter {
@Autowired
private JWTUtility jwtUtility;
@Autowired
private ClientService clientService;
public static String token = null;
public static String userName = null;
public static Long userId = 0L;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authorization = request.getHeader("Authorization");
try{
if (null != authorization && authorization.startsWith("Bearer ")) {
token = authorization.substring(7);
userName = jwtUtility.getEmailAddressFromToken(token);
userId = jwtUtility.getIdFromToken(token);
}
else{
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
ErrorResponse error = new ErrorResponse(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.toString(), "You are not authorized");
final ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(response.getOutputStream(), error);
}
}
catch (Exception e){
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
ErrorResponse error = new ErrorResponse(HttpStatus.FORBIDDEN.value(), HttpStatus.FORBIDDEN.toString(), e.getMessage());
final ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(response.getOutputStream(), error);
}
try{
if (0 != userId && null != userName && SecurityContextHolder.getContext().getAuthentication() == null) {
log.info("token "+token + "\n" + "userId " + userId);
UserDetails userDetails = clientService.getUserById(Long.valueOf(userId), token);
log.info("UserDTO {}", userDetails);
if (jwtUtility.validateTokenTwo(token)) {
log.info("token is valid");
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities()
);
usernamePasswordAuthenticationToken.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request)
);
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
filterChain.doFilter(request, response);
}
catch (HttpClientErrorException e){
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(e.getRawStatusCode());
ErrorResponse error = new ErrorResponse(e.getRawStatusCode(), String.valueOf(e.getRawStatusCode()), e.getStatusCode());
final ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(response.getOutputStream(), error);
}
}
}
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationEntryPoint.class);
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
AuthenticationException e) throws IOException, ServletException {
logger.error("Responding with unauthorized error. Message - {}", e.getMessage());
httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
ErrorResponse error = new ErrorResponse(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.toString(), "You are not authorized");
final ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(httpServletResponse.getOutputStream(), error);
}
}
However, What I would love to do if possible, is a dedicated service that will handle the auth and I can just decode the token from there without having to retrieve it from the header. In a nut-shell, to not have to retrieve token from the header.
Is this possible or what other way regards as standard can I take?