I am implementing RESTful API using javax.ws.rs. The response of the calls that I need to implement requires knowing which user is logged in currently. I tried making a separate call for the user login:
api.myapi.co.uk/authenticate?username=xxxx&password=xxxx
where I basically save the user information is a global variable and then tried to make another call to retrieve information from the database based on the user that has been saved earlier but I find the value as null during the second call. What am I missing? Is my approach wrong? do you have any suggestions please?
Your code probably looks like this, right?
@Path("/")
public class MyResource{
private String username;
private String password;
@Path("authenticate")
public String authenticate(@QueryParam("username") username, @QueryParam("password") password) {
if(!username.equals("zainab") || !password.equals("letmein"))
return "Incorrect username or password";
this.username=username;
this.password=password;
return "Sucessfully authenticated";
}
@Path("secret")
public String secret() {
if(username == null || password == null)
return "Sorry, not authorized";
return "You are authorized: "+username;
}
}
If so, the problem is that JAX-RS creates a new Resource object for each request. A request to "/secret" then uses a new instance of MyResource
, which has username and password as null.
Then, you might think, I'll just make it static
! Then, your resource can't handle concurrent requests. What if Person A calls "/authenticate", then "/secret". Then Person B calls "/secret" without authenticating. He can then access "/secret" without authenticating!
Anyways, this violates the idea of RESTful services. The S in RESTful stands for "Stateless". This means that the server should store no state per client, and possibly give the user a token to pass with concurrent requests.
One possibility is to accept the username and password for every request to secret ("/secret?username=zainab&password=letmein
"). Or you could implement token-based authentication, where the user calls "/authenticate" to get a token, and they pass that token on all later requests. Here is a link to help with that.
Also, note that username and password is usually not send in the URL as a query param, but instead in the Authorization HTTP header as such Authorization: base64encode("USERNAME:PASSWORD")