There are several security schemes that you can implement, you can read the answer to this question something similar.
To give you a concrete solution I will give you an example that I use to secure an API in Jersey using Tokens.
First, once the user logs into your API, you must provide an Accesstoken access token, this token the client must send in the header in each HTTPRequest that he makes to the server after it is achieved.
The header will be called Accesstoken, here a correction since custom headers should start with the prefix X- so you should call it X-Accesstoken or use the standard HTTP header called Authorization.
Now to capture this header the best option is to create an Authorization Filter where I capture this header, in this filter the token is valid and I get the user in this case the Accesstoken stores it in the DB but for better performance you can store it in a In-memory database like Redis.
@NameBinding
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface MiFiltroAutorizacion {}
@ MiFiltroAutorizacion
public class MiFiltroAutorizacionFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
ClienteAccesstokenDAO clienteAccesstokenDAO = new ClienteAccesstokenDAO();
if(requestContext.getHeaders().get("Accesstoken") != null){
String accesstoken =requestContext.getHeaders().get("Accesstoken").get(0).toString();
ClienteAccesstoken clienteAccesstoken = clienteAccesstokenDAO.findByToken(accesstoken);
if(clienteAccesstoken == null)
requestContext.abortWith(
Response.status(Response.Status.UNAUTHORIZED)
.build());
}
}
}
Now you must declare this filter in the web.xml file in the section where you configure your Jersey servlet by adding.
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>com.stackoverflow.es.filtros.MiFiltroAutorizacionFilter</param-value>
</init-param>
Now in each service of your Rest API you must explicitly specify if this service is insured or not with the annotation @MiFiltroAutorizacion in the following way.
@GET
@Path("estadodecuenta")
@Produces(MediaType.APPLICATION_JSON)
@MiFiltroAutorizacion
public Response miRecursoProtegido(@HeaderParam("Accesstoken") String accesstoken) {
.....
return Response.ok().build();
}
If you do not put the annotation in the service, it simply will not go through the authorization filter and therefore it is assumed to be a public resource.
If you want to obtain the user of the 'session' or rather the user who owns the Accesstoken, you can use the ThreadLocal class to store the user of the 'session' at the level of Thread
public class MiAppContext {
public static final ThreadLocal<Usuario> usuarioThreadLocal = new ThreadLocal<Usuario>();
}
You store the user in the ThreadLocal from the filter
@ MiFiltroAutorizacion
public class MiFiltroAutorizacionFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
ClienteAccesstokenDAO clienteAccesstokenDAO = new ClienteAccesstokenDAO();
if(requestContext.getHeaders().get("Accesstoken") != null){
String accesstoken =requestContext.getHeaders().get("Accesstoken").get(0).toString();
ClienteAccesstoken clienteAccesstoken = clienteAccesstokenDAO.findByToken(accesstoken);
MiAppContext.usuarioThreadLocal.set(clienteAccesstoken.getUsuario()); // Agregar usuario al ThreadLocal
if(clienteAccesstoken == null)
requestContext.abortWith(
Response.status(Response.Status.UNAUTHORIZED)
.build());
}
}
}
And then in the service you get the user in this way
@GET
@Path("estadodecuenta")
@Produces(MediaType.APPLICATION_JSON)
@MiFiltroAutorizacion
public Response miRecursoProtegido(@HeaderParam("Accesstoken") String accesstoken) {
Usuario usuarioSesion = MiAppContext.usuarioThreadLocal.get();
.....
return Response.ok().build();
}