Reputation: 3357
I'm using the JAX-RS framework, to make a restless backend for an application, and I have a resource, to authorize, user, as they login, and here is my code in my login resource so far:
@Path("authentication")
public class AuthenticationRessource {
private static Gson gson = new GsonBuilder().setPrettyPrinting().create();
private static AuthenticationFacade authenticationFacade = new AuthenticationFacade();
@GET
@Path("login")
@Produces(APPLICATION_JSON)
public Response authenticateUser(@FormParam("email") String email, @FormParam("password") String password) {
try {
//skal måske ændres til bruger
User user = authenticationFacade.authenticateUser(email, password);
String token = authenticationFacade.generateAuthenticationToken(user);
return Response.ok().header(AUTHORIZATION, "Bearer " + token).build();
} catch (Exception e) {
Response.status(Response.Status.UNAUTHORIZED).build();
System.err.print("det fuckede op, på grund af Thomas har ødelagt koden");
e.printStackTrace();
}
return Response.status(Response.Status.UNAUTHORIZED).build();
}
}
right now I have a resource for authenticating, but maybe this belongs inside of my user resource, and I should assign a path, for authenticating for each user (user, superuser, admin etc.)
Should I add a provider annotation, for this resource, would it make a difference?
Is it the best practice to add AUTHORIZATION to the header, when I add the token?
Upvotes: 3
Views: 3043
Reputation: 136
I will preface this by explaining that I model many of my decisions off of applications created by the JHipster generator: https://www.jhipster.tech/security/
Instead of returning AUTHORIZED or UNAUTHORIZED from the /authenticate endpoint, I return the JWT. The /authenticate endpoint is hit during the login step and the JWT is saved. See the following example:
@PostMapping("/authenticate")
@Timed
public ResponseEntity<JWTToken> authorize(@Valid @RequestBody LoginVM loginVM) {
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(loginVM.getUsername(), loginVM.getPassword());
Authentication authentication = this.authenticationManager.authenticate(authenticationToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
boolean rememberMe = (loginVM.isRememberMe() == null) ? false : loginVM.isRememberMe();
String jwt = tokenProvider.createToken(authentication, rememberMe);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(JWTFilter.AUTHORIZATION_HEADER, "Bearer " + jwt);
return new ResponseEntity<>(new JWTToken(jwt), httpHeaders, HttpStatus.OK);
}
I can then run the stored token through a filter any time an API endpoint is used to determine whether the user is still AUTHENTICATED or UNAUTHENTICATED:
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String jwt = resolveToken(httpServletRequest);
if (StringUtils.hasText(jwt) && this.tokenProvider.validateToken(jwt)) {
Authentication authentication = this.tokenProvider.getAuthentication(jwt);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(servletRequest, servletResponse);
}
And to resolve the JWT token:
private String resolveToken(HttpServletRequest request){
String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7, bearerToken.length());
}
return null;
}
The AUTHORIZATION_HEADER is simply "Authorization":
public static final String AUTHORIZATION_HEADER = "Authorization";
There are some missing pieces I did not include in this response that you can probably infer, but if you are struggling I would encourage you to generate a JHipster monolith application and see first hand a good implementation of JWT which you can model your own implementation after. This is one of my go-tos for help with with Java, Spring, Maven applications.
Upvotes: 2