to me what is needed to prevent outsiders. I just want to respond to requests from those places I have defined.
Example : allowed applications and url
com.x.app
com.y.app
--------- AND ---------
http://www.x.com
Is there an easy way to do this? Best regards!
You should explain what you want clearly. Basically, to do something like this you need to check the $_SERVER['HTTP_USER_AGENT'] attribute of the HTTP header that you are receiving and filter on Android or iPhone keywords.
The best way to build a RESTful API in Laravel is via the routes/api.php
When you add a route to this file, such as the following:
Route::get('/users/list', 'ApiController#userList');
This means when you go to yourwebsite.com/api/users.list, it will execute the given method in the given controller.
As far as authenticating you API users, you can store your users and their API keys in a database and authenticate them before they reach the method by using the magic construct method.
public function __construct() {
$inputKey = filter_input(INPUT_GET, 'key'); //filter input the way you want
if(!isCustomer($inputKey) { //validate api keys in your app somehow
die('Authentication Failure'); //kick the freebooters
}
}
Related
I have this test:
public function test_user_can_access_the_application_page(
{
$user=[
'email'=>'user#user.com',
'password'=>'user1234',
];
$response=$this->call('POST','/login',$user);
$this->assertAuthenticated();
$response->assertStatus(302)
->assertRedirect('/dashboard')
->assertLocation('/dashboard');
$response=$this->call('GET','/application/index');
$response->assertLocation('/application/index');
}
After I log in, it directs me to the dashboard ok until now, but if I want to access the other page after that, I cant. This error comes up.
Expected :'http://mock.test/application/index'
Actual :'http://mock.test'
Aren't multiple calls allowed in the same test, or is another way to access other pages after login?
(Note: It's not possible to use factories for the actingAs so I need to login).
If you can't use factories for actingAs, then you should try with cookie.
Look at the https://github.com/firebase/php-jwt library.
I guess you will need to call the function as an user, since you can only access it logged in. Laravel provides the actingAs() method for such cases.
https://laravel.com/docs/7.x/http-tests#session-and-authentication
You can create a random User who has the permission to log into your app or take a seeded one and call the function acting as the chosen User.
$response=$this->actingAs($user)->call('GET','/application/index');
If you call it without actingAs(), your middleware will redirect you back to the login or home screen (what you defined in the LoginController ).
In my opinion this test case should have its own testing method. I recommend using a test method per route or per use case. It makes your tests clearly arranged and easy to understand.
If you want to be authenticated, the easiest way is to have PHPUnit simulate authentication using the actingAs() method.
This method makes the user authenticated, so you wouldn't want to test the login method with it. You should write your login tests separate from testing the other pages.
To answer your question, yes you can make multiple requests in the same test, but in this case linking the login test to the 'application/index' page likely does not make much sense.
public function test_the_user_can_login()
{
$user = [
'email'=>'user#user.com',
'password'=>'user1234',
];
$response = $this->call('POST','/login',$user);
$this->assertAuthenticated();
$response->assertStatus(302)
->assertRedirect('/dashboard')
->assertLocation('/dashboard');
}
public function test_user_can_access_the_application_page()
{
$user = User::where($email, "user#user.com")->first();
$response = $this->actingAs($user)
->call('GET','/application/index');
$response->assertLocation('/application/index');
}
I experienced that in laravel 8 I use comment #test and involved second test!!! I mean if you use two function for test you must us #test that php artisan test, test both of them.
I have a controller for ProductController. I have 4 standard methods bound to respective HTTP methodslike
public function index() // GET
public function create() // POST
public function update() // PUT
public function destroy() //DELETE
So far so good, but i have to make few other functions like getProductsByCategory, getProductsAttributes() etc etc. After implementing this, Will my API still be called REST ? If not than how can i handle these requirements
Thanks
Resource URI for getProductsByCategory(...):
GET /products?category=books HTTP/1.1
Host: service.org
Resource URI for getProductsAttributes():
GET /products/bmw-528i/attributes HTTP/1.1
Host: service.org
How you implement handling of these request URIs is a implementation detail. If you are using some framework, you can do something like this:
Routes::add("/products/{product-id}/attributes", function($request, $response) {
// do something here
});
But it is a detail that can not affect RESTfullness of your service.
First off, REST is not a strict standard. The methods you posted comply the REST conventions but a REST service must have several other properties. The two most important ones are:
statelessness: no session, no cookies, authorization on a per-request basis
GET requeste never change any resource
There are other ones, feel free to edit or add in the comments.
The way i see such operations on resources implemented most of the time is:
/<resource-name>/<product-id>/<operation>
For example:
GET /product/<product-id>
GET /product/<product-id>/related
POST /product/<product-id>/purchase
GET /categories/tools
My team has an API we wrote in PHP using the Slim Framework. It's being consumed by a web app and a third party mobile app.
We use the standard OAuth 2 workflow to provide access to our resources. We can see if someone is a sending a valid access token along with the API request and that part of the flow makes sense.
The stumbling block we're running into is how to most efficiently authorize access to a resource depending on the permissions of the user associated with the access token.
For the sake of simplicity let's say that we just want to ensure that the owner of the resource in question matches the owner of the access token. To me that seems like something that a route middleware would handle, for every request, before processing the request make sure that the resource owner ID matches that of the access token.
The problem in my mind is that resource permissions aren't necessarily consistent across all routes, a route isn't necessarily going to have an ID in the same section of the URI, it might not have an ID in the URI at all, etc. etc.
My current solution has been to have an authorization utility class that takes in an email and checks it against the user that's currently "logged in" (token owner).
class Authorization() {
checkResourcePermissions($email) {
if (loggedInUser->email == $email) {
return true;
}
}
}
Obviously this is a simplification, but what this means is that since a route middleware won't have the context of a request until that request goes through I will need to call this authorization method inside of every API route, responding with an error if necessary, etc. Our API is fairly large, essentially boiling this down to a large amount of copy and paste which always makes me very nervous.
What am I missing?
I'd suggest going the way using a 'normal' MiddleWare:
First, let's assume you have a class 'user', where you implement your logic to access various types of resources or has specific permissions, given only the $app. It can access the request and get any information from a the HTTP request necessary to identify a single user.
class User{
private $userid=false;
public function __construct($app){
$this->app=$app;
$users_mail=$this->app->request->post('email');
//SELECT user_id FROM USERSTABLE WHERE email = $users_mail
//$this->userid=user_id
}
public function ensureHasAccess($resourceID,$redirect='/noPermission'){
if(!/*some DB Query which returns true if this user may access the given $resourceID*/)
$this->app->redirect($redirect)
}
public function ensureHasRole($role) {
//some other permission checking, like ensureHasAccess();
}
public function ensureIsUser(){
//do Something
}
}
Next, you'll need a MiddleWare which is run before the route is dispatched, and creates an User-Object:
class UserPermissionMiddleware extends \Slim\Middleware{
public function call(){
$this->app->request->user = new User($app);
$this->next->call();
}
}
Then, simply add this Middleware:
$app->add(new UserPermissionMiddleware());
Now, you can modify every route to check the access to a resource, while the resource id (of course) still needs to be supplied by hand, according to the route-specific code:
$app->get('/resource/:id',function($resourceId) use ($app){
$app->request->user->ensureHasAccess($resourceId);
//deliver resource
});
If the user is not allowed to access this resource, the whole process is interrupted (Note that redirect() is implemented using Exceptions!) and another route is executed. You'll still need some code in every single Route, but if there's no consistent way to determine the resource to be acccessed, there'll be no way around this.
Hope this helps you so far. If you have any Questions, feel free to ask!
Requiremen :- Yii, OAuth implemenation to authenticate and fetch user data.
I found out that there are two extensions. Eauth(support OAuth 2.0 and other social networking sites) and Eoauth(OAuth 1.0). Correct me If i am wrong.
I dont have to authenticate any social networking site. It's a different url from where I need to get the data.
Now i could successfully login and authenticate using "eoauth" extension but also I need to fetch information about the user. I don't find any function or way how to fetch data from url which lies under OAuth layer. Does Eauth or Eoauth supports fetching or it has to be custom coded ?
If this extensions does not do this then what is the other way I can authenticate and fetch data ?
Of course, Eauth supports fetching user's data.
Let's see on Eauth structure. We have directories /services, /custom_services and class EOAuthService. EOAuthService contains method makeSignedRequest(), that return the protected resource from third-party site.
So, this method we can call from our serviceClass, that extends EOAuthService. For example, class FacebookOAuthService in /services directory. The class contains protected method fetchAttributes(), it calls method makeSignedRequest($url) and get $info (in JSON) from third-party site (FB in our example). Properties of this object - it's our user's data.
What about /custom_services? The directory contains classes for tuning our "BaseServiceClass".
So, for example, CustomFacebookOAuthService extends FacebookOAuthService extends EOAuthService.
You need create your own class, which will make signed request for your third-party site and get proper response (in JSON, for example). Then fetch gotten info - and voila!
Of course, user must be authenticated by third-party site for fine auth on your application through oauth.
Though Old but You just need to use CURL request to the end URL and you will get your data. I guess those modules doesn't have the function to fetch a data. I hope this might help you. I have used in one of my code and It was successful
public function GetData($url){
$signatureMethod = new OAuthSignatureMethod_HMAC_SHA1();
$request = OAuthRequest::from_consumer_and_token($this->consumer,$this->token, 'GET', $url, array());
$request->sign_request($signatureMethod, $this->consumer, $this->token);
$fetchUrl = $request->to_url();
$response = Yii::app()->CURL->run($fetchUrl);
return json_decode($response);
}
I have 3 controllers, Tokens, Stores and Users.
Token is related to the two other models, for each token there is a owner-type and owner-id.
There is also a function in both User_controller and Store_controller, called EmailTokenToUser which send the activation link to the person that registered a user or a store.
My question is: should i pass the function to the token?
if so, how should i call it? (requestAction is a bad idea, creating an object just for one function..)
any ideas?
To reuse code you should pass it to token's MODEL not the controller. That is the way it should be not the only way. To use it you should NOT use requestAction even if is inside the controller (again it is the way it should be you CAN do it with requestAction). You can do this in two ways.
App:import('model', Token');
Token::myFunction($args);
OR
$token = ClassRegistry:init('Token');
$token->myFunction($args);
OR (if you are colling it from inside a controller you may use also)
$this->loadModel('Token');
$this->Token->myFunction($args);
This is if you put it in the Token model the function. If not and go with the controller way you should do it like this
App:import('controller', 'Tokens');
TokensController::myFunction($args);
OR
App:import('controller', 'Tokens');
$token = new TokensController();
$token->myFunction($args);
Hope it helps you :)