Jump to content

Changing PHP site to use REST for data access and need some help


graffix857

Recommended Posts

Hi all, I currently have a web app (php my first once actually) that accesses a MySql database.  How I was handling the login was like this:  This user enters the username and pw which gets sent to a stored procedure.  If they successfully are validated I output a record (contains userid, first name and if they are logged in or not) and I set two session variables, 1 that stores a boolean if they are logged in (1 if they are, 0 if they are not) and the other stores the user id of that user (so I can use later to make sure they only get their data).  I then check these session variables to 1.Make sure they are logged in and 2. Make sure they are only requesting their data (userid) 

 

I'm now going to be working on an Android app and make all the data access stuff a rest api that both the app and the website can consume.  I modified the login stored procedure so it now will return a token as well. The token is generated on the DB(a hashed value of a couple of fields concatenated).  When they log in successfully  the token generated is stored in a user token table.(one user, one token)  The table also stores a token_expire timestamp.  Every time they log in a new token is created(and token_expire is updated).  If they try to do something after the token expired (based on the token_expire field) then it should redirect them to login so a new token can be created. 

 

 When I do the Android app, dealing with this and storing this token on the client is easy and there are many ways to store it (I was thinking storing it in a local sqlite table, shared_prefs (prob not the best way) etc..) and I would just parse through the json result. So keeping track of the token is easy with the app but my problem comes in with the PHP web site. 

 

So I'm faced with two issues: 

 

Issue 1. Right now I have a php form (with login and password fields) and it posts to a login process page which calls the stored procedure and if all is good redirects them to a dashboard page.  Now if I use rest the post action would be something like: api/users/login  instead of loginprocess.php correct? But then the api just spits out json and I'm not sure how to hand the result from the api to the php code. As when I change the post action I just get a white page with the json result string.  So I need help knowing what to do once the api returns the result.  Does this have to be called differently than a normal form submit? Do I just have the form submit call a js funcation that makes the call to the page and parses the result? Similar to something like this but instead of passing the cookie passing the login information?

 



 
$opts = array('http' => array('header'=> 'Cookie: ' . $_SERVER['HTTP_COOKIE']."\r\n"));
$context = stream_context_create($opts);
session_write_close(); // unlock the file
$contents = file_get_contents(url, false, $context);


 

Issue 2. Once this token is generated in MySQL and sent back to the api, I need to pass it back to the PHP(related to #1) but How do I store it so that other pages of the site can send it when it requests the data?  I know it has to be sent in the header in future requests  and that's not my issue.  My issue is where do I store the token on the web client so that other pages can use it?  Should I store it in a client cookie? (but then doesn't this go against rest?) Store it in local storage?  I'm pretty new to PHP and REST (was a classic ASP guy and just getting back into this stuff. This project is the first personal project for myself to learn this stuff and get the rust out) so I'm just trying to figure out the best way.  I do not want to use sessions as that violates REST.  I also do not want to use oauth or any 3rd party solution.

 

I have been reading a lot about this but I'm still unclear as to how to go about these changes to the web version of the app and have it function properly.  This is what my rest login api looks like so far (I know this will have to change but I'm stuck here with it):

 

   

function loginUser() {
    global $app;
    $req = $app->request(); 
    $paramUsername = $req->params('username'); 
    $paramPassword = $req->params('password');
    $sql = "CALL checkPassword(:username,:password)";
    try {
    $dbCon = getConnection();
    $stmt = $dbCon->prepare($sql);
    $stmt->bindParam("username", $paramUsername);
    $stmt->bindParam("password", $paramPassword);
    $stmt->execute();
    $result = $stmt->fetchAll();
    $loggedin=$result[0]["loggedin"];
    $uid= $result[0]["uid"];
    $fname=$result[0]["firstname"];
    $token=$result[0]["token"];
    $response["uid"]=$uid;
    $response["loggedin"]=$loggedin;
    $response["firstname"]=$fname;
    $response["token"]=$token;
    echo  json_encode($response);
    $dbCon = null;
    }
    catch(PDOException $e) {
    echo '{"error":{"text":'. $e->getMessage() .'}}'; 
    }
    }


 

Which returns:

 

   

{"uid":"100","loggedin":"1","firstname":"John","token":"f0165d67221563bef150018276f4f77b7bd1e1763223e"}


 

Here is what the form looks like calling the api currently:

 



<form id="login" method="post" action="webservices/api/users/login">
  <input class="my-class" style="width:20em" type="email" name="username" required>
  <input class="my-class" style="width:20em"  type="password" name="password" required>
  <button type="submit" id="SubmitButton" name="submit" "></button>
 </form>


 

Can anyone recommend the best way to deal with these two issues?  Any help would be appreciated.  Oh I should mention I'm using slim to help with the rest api's.

 

TIA

Link to comment
Share on other sites

There are two main types of APIs and I think this may be confusing you:

1. An external API, like the kind you would put at a URL like /api/users/login. Javascript/AJAX on your site can call it, other third-party services can call it. Your PHP does not call it. This API is not necessary for a "traditional" site where you have a POSTed login form, but is important if you want to use AJAX (or let other people call your API).

2. An internal API. This isn't accessible by anything but your own PHP code. Your stored procedure to login is an example of this: it provides an interface between "you" (your PHP code) and "the service" (the user login data in the database.) If you wrote some generic code to call it, as in some User class with a login() method, that itself would be a sort of API because it is the interface between "you" (other PHP code across the site, like the code for loginprocess.php) and "the service" (whatever thing is in place that deals with logging users in).

 

The API you have now that returns JSON is fine. The login token is fine; I suggest some mechanism to refresh a token, however, or else people will be forced to log in every X minutes regardless of whether they were active or not. (You can refresh on a hit to an API and on a page load on the site.) Unless you're talking about a "remember me"-type token which is used to log someone in automatically, but your description doesn't quite sound like that.

 

Your PHP does *not* use the external API, and this is where those two types of APIs come into play. If your PHP used it, it would have to call a page on its own website, which would execute code elsewhere in parallel, and after all is said and done you've created a lot of needless work for your code and your server.

What you should do is create the internal API. This is the code that connects to the database, runs the stored procedure, and returns whatever information. It will have two consumers: loginprocess.php calls it when someone submits the form, and the /api/users/login API calls it when someone invokes it. Thus the two execution flows are

'user -> submits login form on website -> loginprocess.php -> internal API --+
                                                                             |
                                                                             v
                                                                          database
                                                                             |
             redirect user or whatever <- loginprocess.php <- internal API <-+'
'  login page -> AJAX -> /api/users/login -> internal API --+
                                                            |
                                                            v
                                                         database
                                                            |
JS reacts <- response <- /api/users/login <- internal API <-+'
Edited by requinix
  • Like 1
Link to comment
Share on other sites

There are two main types of APIs and I think this may be confusing you:

1. An external API, like the kind you would put at a URL like /api/users/login. Javascript/AJAX on your site can call it, other third-party services can call it. Your PHP does not call it. This API is not necessary for a "traditional" site where you have a POSTed login form, but is important if you want to use AJAX (or let other people call your API).

2. An internal API. This isn't accessible by anything but your own PHP code. Your stored procedure to login is an example of this: it provides an interface between "you" (your PHP code) and "the service" (the user login data in the database.) If you wrote some generic code to call it, as in some User class with a login() method, that itself would be a sort of API because it is the interface between "you" (other PHP code across the site, like the code for loginprocess.php) and "the service" (whatever thing is in place that deals with logging users in).

 

The API you have now that returns JSON is fine. The login token is fine; I suggest some mechanism to refresh a token, however, or else people will be forced to log in every X minutes regardless of whether they were active or not. (You can refresh on a hit to an API and on a page load on the site.) Unless you're talking about a "remember me"-type token which is used to log someone in automatically, but your description doesn't quite sound like that.

 

Your PHP does *not* use the external API, and this is where those two types of APIs come into play. If your PHP used it, it would have to call a page on its own website, which would execute code elsewhere in parallel, and after all is said and done you've created a lot of needless work for your code and your server.

What you should do is create the internal API. This is the code that connects to the database, runs the stored procedure, and returns whatever information. It will have two consumers: loginprocess.php calls it when someone submits the form, and the /api/users/login API calls it when someone invokes it. Thus the two execution flows are

'user -> submits login form on website -> loginprocess.php -> internal API --+
                                                                             |
                                                                             v
                                                                          database
                                                                             |
             redirect user or whatever <- loginprocess.php <- internal API <-+'
'  login page -> AJAX -> /api/users/login -> internal API --+
                                                            |
                                                            v
                                                         database
                                                            |
JS reacts <- response <- /api/users/login <- internal API <-+'

 

I think I understand it much better now.  So basically the site won't use the REST API Only the mobile app?.  I guess the only time your site would really need to call an external api is if it was a server hosted elsewhere or something and not on the traditional site.  Is that correct?  Your last paragraph threw me a little.    Using the login function I pasted above, suppose that's my internal api.  How will that internal api know if it was the site that called it or if it was the external api that called it and know what to return based on that?  Would it be bad to just leave the site as is and just focus on the external api for the mobile app to consume?  

 

Thanks for your response as I think it is much clearer now then it was before. haha

Link to comment
Share on other sites

So basically the site won't use the REST API Only the mobile app?.

Depends what you mean by "the site". The PHP code behind your site will not use it, but the AJAX and Javascript on your site will - that's how it communicates with the server. The mobile app would use it too.

Basically it comes down to whether the thing is running on your server (PHP code) or not (AJAX runs on the browser, mobile app runs on mobile).

 

I guess the only time your site would really need to call an external api is if it was a server hosted elsewhere or something and not on the traditional site.  Is that correct?

...Maybe? I don't think I understand what you're saying.

 

You're developing a site which includes a user login component. The external API is /api/users/login and is the only way code that is not running on your actual server can interact with the server. So AJAX and third-parties would use it. (For all intensive porpoises :D your mobile app is "third-party" because it's not running on your server - you just happen to be its developer too.) The internal API is what the stuff that is running on your actual server, as in the actual PHP code, interacts with.

 

Or I guess put another way, consider what the code for /api/users/login would look like. You receive some input (GET, POST, whatever), somehow get that to your stored procedure, receive the token, and return it however you'd like as output. The question is exactly what the "somehow get that to your stored procedure" is. Obviously your code needs some way to communicate with the database, but it could do so directly (by setting up a database connection, binding parameters, and executing SQL) or indirectly (by calling other code which communicates with the database). If you do it directly then that's alright. If you do it indirectly then whatever you use there to fill in the gap would be the internal API.

 

Directly:

<?php // /api/users/login

$email = $_POST["email"];
$password = $_POST["password"];

// this example here uses output parameters from the proc. yours simply returns a resultset
$connection = new mysqli_or_pdo_or_whatever(/* parameters */);
$query = $connection->create_a_statement_for_the_stored_procedure();
$query->bind_the_parameters_to_the_query($email, $password, $variable_to_receive_the_token);
$query->execute();

return json_encode(array(
	"token" => $variable_to_receive_the_token
));
Indirectly with an internal API.

<?php // /api/users/login

$email = $_POST["email"];
$password = $_POST["password"];

$user = User::login($email, $password);
// User::login will somehow, directly or indirectly (via yet another internal API), communicate with the database to log in

return json_encode(array(
	"token" => $user->token
));
The internal API has a number of advantages, most notable being:

- Much less code

- The exact mechanism of how to log in are abstracted away and the /api/users/login doesn't need to know them

- The mechanism can change so long as the API ("provide me with an email and password and I will return you a User object") looks the same

 

Your last paragraph threw me a little.    Using the login function I pasted above, suppose that's my internal api.  How will that internal api know if it was the site that called it or if it was the external api that called it and know what to return based on that?

Therein lies a problem with your API. Or rather, the code you have in place to perform the work for your API.

 

Yes, you are correct in that it is like an internal API. Except it has too much knowledge about how it's being called: the information is coming from a request, it knows the parameters are called "username" and "password", and it outputs JSON according to the result. You won't be able to reuse that anywhere and reusability is a big principle behind an API - internal or external.

 

What you should do is split it apart into two pieces: one to receive data from the request and send whatever output, another to handle just the login.

// this function can handle a login that originates anywhere
// it returns an array in a specific format that is independent of how the calling code needs to react
function loginUser($username, $password) {
	try {
		$sql = "CALL checkPassword(:username, :password)";
		$dbCon = getConnection();
		$stmt = $dbCon->prepare($sql);
		$stmt->bindParam("username", $username);
		$stmt->bindParam("password", $password);
		$stmt->execute();
		$result = $stmt->fetchAll();
		return array(
			"loggedin" => $result[0]["loggedin"],
			"uid" => $result[0]["uid"],
			"firstname" => $result[0]["firstname"],
			"token" => $result[0]["token"],
			"potentially" => $result[0]["field1"],
			"other" => $result[0]["field2"],
			"useful" => $result[0]["field3"],
			"data" => $result[0]["field4"]
		);
	} catch (PDOException $e) {
		// calling code should not need to know about PDOException or anything specific like that
		// wrap this into a more general exception
		throw new loginUserException("Failed to log in", 0, $e);
	}
}

// this function can handle a login but only if the information comes from the request in
// a specific format and only if the response can be JSON in a specific format
function loginUserFromRequest() {
	global $app;
	$req = $app->request();
	$paramUsername = $req->params("username");
	$paramPassword = $req->params("password");
	try {
		$return = loginUser($paramUsername, $paramPassword);
		// the function returns an array with a lot of stuff. we only care about some of it
		echo json_encode(array(
			"uid" => $return["uid"],
			"loggedin" => $return["loggedin"],
			"firstname" => $return["firstname"],
			"token" => $return["token"]
		));
	} catch (loginUserException $lue) {
		echo json_encode(array(
			"error" => array(
				// notice that this will always say "Failed to log in"
				// never expose database error messages!
				"text" => $lue->getMessage()
			)
		));
	}
}
loginUserFromRequest() is a mere function, but provides the backbone for the /api/users/login external API. In an MVC architecture, it is your controller (and view).

loginUser() is an internal API and provides the backbone for other code in your application to log a user in. You can reuse it anywhere that you have a username and password.

loginprocess.php would have code that resembles loginUserFromRequest() in that it gets the username and password from the request, passes it to loginUser(), receives the result, and displays something to the user.

 

Would it be bad to just leave the site as is and just focus on the external api for the mobile app to consume?

Let me turn the question around on you: is the site in a state where you can leave it alone? If so, feel free to focus on the external API. You'll probably end up refactoring parts of the site as you go anyways. But if there is something wrong with the site and it's in a state where you shouldn't leave it alone and go work on something else, then... well, there's your answer. Edited by requinix
humor
Link to comment
Share on other sites

Depends what you mean by "the site". The PHP code behind your site will not use it, but the AJAX and Javascript on your site will - that's how it communicates with the server. The mobile app would use it too.

Basically it comes down to whether the thing is running on your server (PHP code) or not (AJAX runs on the browser, mobile app runs on mobile).

 

...Maybe? I don't think I understand what you're saying.

 

You're developing a site which includes a user login component. The external API is /api/users/login and is the only way code that is not running on your actual server can interact with the server. So AJAX and third-parties would use it. (For all intents and purposes, your mobile app is "third-party" because it's not running on your server - you just happen to be its developer too.) The internal API is what the stuff that is running on your actual server, as in the actual PHP code, interacts with.

 

Or I guess put another way, consider what the code for /api/users/login would look like. You receive some input (GET, POST, whatever), somehow get that to your stored procedure, receive the token, and return it however you'd like as output. The question is exactly what the "somehow get that to your stored procedure" is. Obviously your code needs some way to communicate with the database, but it could do so directly (by setting up a database connection, binding parameters, and executing SQL) or indirectly (by calling other code which communicates with the database). If you do it directly then that's alright. If you do it indirectly then whatever you use there to fill in the gap would be the internal API.

 

Directly:

<?php // /api/users/login

$email = $_POST["email"];
$password = $_POST["password"];

// this example here uses output parameters from the proc. yours simply returns a resultset
$connection = new mysqli_or_pdo_or_whatever(/* parameters */);
$query = $connection->create_a_statement_for_the_stored_procedure();
$query->bind_the_parameters_to_the_query($email, $password, $variable_to_receive_the_token);
$query->execute();

return json_encode(array(
	"token" => $variable_to_receive_the_token
));
Indirectly with an internal API.

<?php // /api/users/login

$email = $_POST["email"];
$password = $_POST["password"];

$user = User::login($email, $password);
// User::login will somehow, directly or indirectly (via yet another internal API), communicate with the database to log in

return json_encode(array(
	"token" => $user->token
));
The internal API has a number of advantages, most notable being:

- Much less code

- The exact mechanism of how to log in are abstracted away and the /api/users/login doesn't need to know them

- The mechanism can change so long as the API ("provide me with an email and password and I will return you a User object") looks the same

 

Therein lies a problem with your API. Or rather, the code you have in place to perform the work for your API.

 

Yes, you are correct in that it is like an internal API. Except it has too much knowledge about how it's being called: the information is coming from a request, it knows the parameters are called "username" and "password", and it outputs JSON according to the result. You won't be able to reuse that anywhere and reusability is a big principle behind an API - internal or external.

 

What you should do is split it apart into two pieces: one to receive data from the request and send whatever output, another to handle just the login.

// this function can handle a login that originates anywhere
// it returns an array in a specific format that is independent of how the calling code needs to react
function loginUser($username, $password) {
	try {
		$sql = "CALL checkPassword(:username, :password)";
		$dbCon = getConnection();
		$stmt = $dbCon->prepare($sql);
		$stmt->bindParam("username", $username);
		$stmt->bindParam("password", $password);
		$stmt->execute();
		$result = $stmt->fetchAll();
		return array(
			"loggedin" => $result[0]["loggedin"],
			"uid" => $result[0]["uid"],
			"firstname" => $result[0]["firstname"],
			"token" => $result[0]["token"],
			"potentially" => $result[0]["field1"],
			"other" => $result[0]["field2"],
			"useful" => $result[0]["field3"],
			"data" => $result[0]["field4"]
		);
	} catch (PDOException $e) {
		// calling code should not need to know about PDOException or anything specific like that
		// wrap this into a more general exception
		throw new loginUserException("Failed to log in", 0, $e);
	}
}

// this function can handle a login but only if the information comes from the request in
// a specific format and only if the response can be JSON in a specific format
function loginUserFromRequest() {
	global $app;
	$req = $app->request();
	$paramUsername = $req->params("username");
	$paramPassword = $req->params("password");
	try {
		$return = loginUser($paramUsername, $paramPassword);
		// the function returns an array with a lot of stuff. we only care about some of it
		echo json_encode(array(
			"uid" => $return["uid"],
			"loggedin" => $return["loggedin"],
			"firstname" => $return["firstname"],
			"token" => $return["token"]
		));
	} catch (loginUserException $lue) {
		echo json_encode(array(
			"error" => array(
				// notice that this will always say "Failed to log in"
				// never expose database error messages!
				"text" => $lue->getMessage()
			)
		));
	}
}
loginUserFromRequest() is a mere function, but provides the backbone for the /api/users/login external API. In an MVC architecture, it is your controller (and view).

loginUser() is an internal API and provides the backbone for other code in your application to log a user in. You can reuse it anywhere that you have a username and password.

loginprocess.php would have code that resembles loginUserFromRequest() in that it gets the username and password from the request, passes it to loginUser(), receives the result, and displays something to the user.

 

Let me turn the question around on you: is the site in a state where you can leave it alone? If so, feel free to focus on the external API. You'll probably end up refactoring parts of the site as you go anyways. But if there is something wrong with the site and it's in a state where you shouldn't leave it alone and go work on something else, then... well, there's your answer.

 

 

Every thing is hosted on my server.  But I get it now I think.  Yes, the site (my php web app) is working as expected so far. When I say site I mean the web UI php app that's already up and running.  I had just decided to write a mobile app version of it and started looking up database access an mobile apps.   I wanted to write as little code as possible and reuse the code.  That's why I was trying to make the external api work with the internal php app but can see I had it all wrong.  

That last little code snippet made sense to me and I think made it click.  Let me just run through it and make sure I understand.

 

 So if the user logs in from the php web ui form, loginprocess.php would call loginuser(), gets the array that it returns, parses through the array it and store that in my session variables and such.  For the api that the mobile app will access:   the api/user/login external api is passed the username and password from the mobile app as a post request,  which is then passed to loginuser(), the array that is returned is encoded into json  which the mobile app then parses through and stores what it needs to store from the result.. If that's correct then I believe I got it and seeing it like that made sense to me.

 

Oh and what you mentioned earlier about having the token refresh. Would it be bad to have the token_expire update with every request from the external api? Like when it's validated for example.  If it's valid, extend the expiration time .

 

And one last question about he token. For the web UI:  Since the stored procedure returns the token field, should I just use that and store that in a session variable or cookie  and validate it against the one stored in the db every time I try to access data the same as I would with the external api or is that not really needed? just set a session variable flag after they successfully login and check that flag before doing something,  not ever taking the token or token expire into consideration on the web UI and just letting the session handle it like it normally would?

 

Sorry for such the noob questions.  I haven't really done this stuff since classic ASP was first released!  I'm familiar with server side stuff from that but just old stuff and it seems like a lot has changed.  This is the first time I've dealt with PHP and the first experience I have writing any kind of web service(on top of that I did some of the web UI with polymer which I have never used before either).  It's been an adventure that's for sure. I was also reading a lot on stackoverflow which I see now probably made me more confused than anything else and lead me down many dead ends..  

 

I really really do appreciate your very detailed answer and taking the time to help me understand this!

Edited by graffix857
Link to comment
Share on other sites

Depends what you mean by "the site". The PHP code behind your site will not use it, but the AJAX and Javascript on your site will - that's how it communicates with the server. The mobile app would use it too.

Basically it comes down to whether the thing is running on your server (PHP code) or not (AJAX runs on the browser, mobile app runs on mobile).

 

...Maybe? I don't think I understand what you're saying.

 

You're developing a site which includes a user login component. The external API is /api/users/login and is the only way code that is not running on your actual server can interact with the server. So AJAX and third-parties would use it. (For all intents and purposes, your mobile app is "third-party" because it's not running on your server - you just happen to be its developer too.) The internal API is what the stuff that is running on your actual server, as in the actual PHP code, interacts with.

 

Or I guess put another way, consider what the code for /api/users/login would look like. You receive some input (GET, POST, whatever), somehow get that to your stored procedure, receive the token, and return it however you'd like as output. The question is exactly what the "somehow get that to your stored procedure" is. Obviously your code needs some way to communicate with the database, but it could do so directly (by setting up a database connection, binding parameters, and executing SQL) or indirectly (by calling other code which communicates with the database). If you do it directly then that's alright. If you do it indirectly then whatever you use there to fill in the gap would be the internal API.

 

Directly:

<?php // /api/users/login

$email = $_POST["email"];
$password = $_POST["password"];

// this example here uses output parameters from the proc. yours simply returns a resultset
$connection = new mysqli_or_pdo_or_whatever(/* parameters */);
$query = $connection->create_a_statement_for_the_stored_procedure();
$query->bind_the_parameters_to_the_query($email, $password, $variable_to_receive_the_token);
$query->execute();

return json_encode(array(
	"token" => $variable_to_receive_the_token
));
Indirectly with an internal API.

<?php // /api/users/login

$email = $_POST["email"];
$password = $_POST["password"];

$user = User::login($email, $password);
// User::login will somehow, directly or indirectly (via yet another internal API), communicate with the database to log in

return json_encode(array(
	"token" => $user->token
));
The internal API has a number of advantages, most notable being:

- Much less code

- The exact mechanism of how to log in are abstracted away and the /api/users/login doesn't need to know them

- The mechanism can change so long as the API ("provide me with an email and password and I will return you a User object") looks the same

 

Therein lies a problem with your API. Or rather, the code you have in place to perform the work for your API.

 

Yes, you are correct in that it is like an internal API. Except it has too much knowledge about how it's being called: the information is coming from a request, it knows the parameters are called "username" and "password", and it outputs JSON according to the result. You won't be able to reuse that anywhere and reusability is a big principle behind an API - internal or external.

 

What you should do is split it apart into two pieces: one to receive data from the request and send whatever output, another to handle just the login.

// this function can handle a login that originates anywhere
// it returns an array in a specific format that is independent of how the calling code needs to react
function loginUser($username, $password) {
	try {
		$sql = "CALL checkPassword(:username, :password)";
		$dbCon = getConnection();
		$stmt = $dbCon->prepare($sql);
		$stmt->bindParam("username", $username);
		$stmt->bindParam("password", $password);
		$stmt->execute();
		$result = $stmt->fetchAll();
		return array(
			"loggedin" => $result[0]["loggedin"],
			"uid" => $result[0]["uid"],
			"firstname" => $result[0]["firstname"],
			"token" => $result[0]["token"],
			"potentially" => $result[0]["field1"],
			"other" => $result[0]["field2"],
			"useful" => $result[0]["field3"],
			"data" => $result[0]["field4"]
		);
	} catch (PDOException $e) {
		// calling code should not need to know about PDOException or anything specific like that
		// wrap this into a more general exception
		throw new loginUserException("Failed to log in", 0, $e);
	}
}

// this function can handle a login but only if the information comes from the request in
// a specific format and only if the response can be JSON in a specific format
function loginUserFromRequest() {
	global $app;
	$req = $app->request();
	$paramUsername = $req->params("username");
	$paramPassword = $req->params("password");
	try {
		$return = loginUser($paramUsername, $paramPassword);
		// the function returns an array with a lot of stuff. we only care about some of it
		echo json_encode(array(
			"uid" => $return["uid"],
			"loggedin" => $return["loggedin"],
			"firstname" => $return["firstname"],
			"token" => $return["token"]
		));
	} catch (loginUserException $lue) {
		echo json_encode(array(
			"error" => array(
				// notice that this will always say "Failed to log in"
				// never expose database error messages!
				"text" => $lue->getMessage()
			)
		));
	}
}
loginUserFromRequest() is a mere function, but provides the backbone for the /api/users/login external API. In an MVC architecture, it is your controller (and view).

loginUser() is an internal API and provides the backbone for other code in your application to log a user in. You can reuse it anywhere that you have a username and password.

loginprocess.php would have code that resembles loginUserFromRequest() in that it gets the username and password from the request, passes it to loginUser(), receives the result, and displays something to the user.

 

Let me turn the question around on you: is the site in a state where you can leave it alone? If so, feel free to focus on the external API. You'll probably end up refactoring parts of the site as you go anyways. But if there is something wrong with the site and it's in a state where you shouldn't leave it alone and go work on something else, then... well, there's your answer.

 

 

 

I've been working on reworking the php web UI to use an internal API..Once that's done I'll start to modify my external api

 

It seems to all make sense to me now.  Thanks again for everything!

Link to comment
Share on other sites

Oh and what you mentioned earlier about having the token refresh. Would it be bad to have the token_expire update with every request from the external api? Like when it's validated for example.  If it's valid, extend the expiration time .

That'd be fine. While websites should definitely update the expiration time, APIs are a little more flexible. You could enforce a hard limit of X minutes on just the API if you expect whatever operations (eg, with the mobile app) will last much less than that time. However once that time is up the user will have to log in again; the app could keep the username and password in memory (it really shouldn't if at all possible) but otherwise the user would need to type the information in again.

 

So yeah, updating is fine.

 

And one last question about he token. For the web UI:  Since the stored procedure returns the token field, should I just use that and store that in a session variable or cookie  and validate it against the one stored in the db every time I try to access data the same as I would with the external api or is that not really needed? just set a session variable flag after they successfully login and check that flag before doing something,  not ever taking the token or token expire into consideration on the web UI and just letting the session handle it like it normally would?

The latter (setting a flag) is probably fine for the site. It's more of a technical question: would the site actually need to use the token later? You could impose a security layer within the stored procedures such that "sensitive" operations require a token before they can perform any action. For example, changing a password could require a username, password, and token, where it uses the token (after validating it, of course) to identify the user performing the update and checks whether that user is allowed to do so: if the token corresponds to that user or to a particular sort of administrative user that is allowed to change passwords then update the password, else fail.

 

The API would work differently since APIs don't really use sessions. I mean you could, but then you force the consumer to deal with cookies and that can suck. If you decide against the added security then your API would be the one that validates the token (via a stored procedure) and does the update.

 

Sorry for such the noob questions.

Questions are good. There should never come a point in your life where you don't have questions to ask. About anything.

 

It would be nice if other people reading this thread commented too, though.

Edited by requinix
Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.