I'm building an application via slim framework and it's slim-jwt-auth middleware.
I installed it, and it works fine but I'm a bit confused with the passthrough possibility.
My RequestPathRule:
new \Slim\Middleware\JwtAuthentication\RequestPathRule([
"path" => ["/api"],
"passthrough" => ["/api/auth", "/api/users", "/api/products", "/api/orders", "/api/streets",
"/api/reservations", "/api/feedbacks", "api/menu"]
])
And my RequestMethodRule:
new \Slim\Middleware\JwtAuthentication\RequestMethodRule([
"passthrough" => ["POST", "GET"]
])
But it allows these methods to all endpoints. Actually, I want to let POST only to /api/auth, /api/orders, /api/reservations and /api/feedbacks, and GET for every endpoint except /api/users.
How is this possible?
Thank you in advance.
It would be interesting to see which are your routes, but basically in your current configuration your are saying:
1) DON'T Authenticate "/api/auth", "/api/users", "/api/products", "/api/orders", "/api/streets", "/api/reservations", "/api/feedbacks" and "api/menu" (rest of endpoints under /api MUST be authenticated)
2) AND also dont authenticate whatever POST or GET request
some examples:
PUT /api/users NEVER will be authenticate since /api/users is in
RequestPathRule
GET /api/users NEVER will be authenticate since /api/users is in
RequestPathRule AND GET is in RequestMehtodRule
PUT /api/whatever ALWAYS will be authenticate since /api/users is
NOT in RequestPathRule AND GET is NOT in RequestMethodRule
Basically rules work like an OR comparison operator and in the right moment an endpoint is in RequestPathRule OR a request method is in RequestMethodRule the request will be not authenticated.
A better approach could be trying not to use RequestMethodRule as much as possible (generally you just include OPTIONS method) and play with different paths.
In a normal web application you will provide a public API path to your clients under /api and the only endpoint you don't generally authenticate is /api/login (or /api/auth in your example) the rest of the endpoint under /api are authenticated. If your provide another set of endpoints which you don't want to authenticate you provide another different path like /service and your don't include it as "path" in RequestPathRule. If you need a set of endpoint ALL authenticated you create all of then under a new path, let's say /admin and you include on path in RequestPathRule and you don't add any "passthrough" for them.
So the idea is play with different path and just add those methods under RequestMethodRule for specific use cases. Moreover, in that way you will have a better clear and organized API.
Looking at your endpoints I recommend you create different path for most of them, so instead of having "/api/auth", "/api/users", "/api/products", "/api/orders" I would suggest you to have "/auth", "/user", "/product", "/order"... and you can add a RequestPathRule and RequestMethodRule for every path.
To be honest, as the slim-jwt-auth middleware is thought, it's difficult to provide CRUD operations over same endpoint, let's say you have GET, POST, PUT and DELETE over /user and you want just authenticate POST, PUT and DELETE. For that case you could have 2 options:
create differen endpoint for each verb like: GET /user/all, POST /user/add, PUT /user/edit and DELETE /user/delete (which is a bad practice
Create or extend your RequestPathRule and RequestMethodRule callable with the only conditions that they must implement RuleInterface and adapt them to your needs (highly recommended)
If you choose the 2nd option you only have to add those callable to the rules option. Something like this:
$app->add(new \Slim\Middleware\JwtAuthentication([
"rules" => [
new \My\Auth\Rules\RequestPathRule([
"path" => "/",
"passthrough" => []
]),
new \My\Auth\Rules\RequestMethodRule([
"passthrough" => ["OPTIONS"]
])
]
]));
Related
Currently, I've got the following route in my web app.
Route::get(__('routes.account.dogs'),
[DogController::class, 'index'])->name('dog.index')->middleware('auth');
I specify the URL translation for the route in two different language files.
return [
//Account
'account' => [
'dogs' => 'honden',
]
];
When I send a queued email with this link, I want to translate the link on the user's locale (saved in the database). So I want to get this route based on the user's locale, but app()->setLocale($user->locale); cannot be used because it's a queued job. How can I fix this?
In a perfect world it would be something like:
route('dog.index', [], $user->locale);
laravel __() helper function also accepts the optional 3rd argument $locale for setting the locale to translate.
So you could use the $user->locale in the helper as follows.
url(__('account.dogs', [], $user->locale));
As #Vincent Decaux suggested, you need a library to make your life easier. You could use the one they use or the one I use arcanedev/localization.
Once you set a middleware, everything will be taken care of. But I am concerned regarding your comment:
Yes indeed! but then I still need to do something with the domain. For example .de or .com
Why not use the current domain (.com?) and simply add a directory /en or whatever locale you need instead? It seems inconvenient to me to change the entire domain.
When you use Mail::to(), you can use locale() to choose the translation
Mail::to($user->email)
->locale($user->locale)
->queue(new YourEmail());
https://laravel.com/docs/9.x/mail#localizing-mailables
I'm new to Yii2. I want to implement Oauth2 with Resource owner credentials grant type in Yii2.
For that, I found this Yii2 specific library:
https://github.com/Filsh/yii2-oauth2-server
But the documentation is poor and doesn't show exact steps to use it.
So far I did this:
1) Install package using composer
2) Added module configuration into common/config/main.php
Now I'm getting confused for the next steps.
It says to create a class called "PublicKeyStorage". Is it really necessary or optional step? If yes then where should I create this file? Do I need to create privkey.pem and pubkey.pem file manually? If yes there what content should they have?
Next, it says to extend the common\models\User model. So where should I create this file? Into frontend/models?
3) Next, it says to run the package migration which is clear.
4) Next, it says to set URLs, which is also clear.
5) Next, it says to set controller, I believe it is to verify incoming token. Am I correct?
The last question I have is that what URLs should I hit to get the access token? Is it /oauth2/token?
If you want to get JSON Web Token (JWT) instead of the conventional token, you will need to set 'useJwtToken' => true in module and then define two more configurations: 'public_key' => 'app\storage\PublicKeyStorage' which is the class that implements PublickKeyInterface and 'access_token' => 'app\storage\JwtAccessToken' which implements JwtAccessTokenInterface.php.
5) Next, it says to set controller, I believe it is to verify incoming token. Am I correct?
A) Yes
I'm using the HMVC package to consume my own API. However it also includes some POST requests which require authenticaton. Obviously I can't just dump in my password in the request nor do I find ENV variables an elegant solution.
Is there a way to check inside the basic auth filter whether the request is made internally?
The filter is applied to the controller, not the route
First option
You could add the exception test on the filter, so that you only apply the filter rule if the request is not from localhost.
Second option
You would apply the filter on the Route, so that you wouldn't have problems accessing the controller locally.
Route::get('profile', array('before' => 'auth', function()
{
// Only authenticated users may enter...
}));
Source: http://laravel.com/docs/4.2/security#protecting-routes
Third option
It doesn't seem an elegant solution either, but a workaroung would be to look if the request comes from localhost, you could manually authenticate the user.
$user = User::find(1);
Auth::login($user);
Source: http://laravel.com/docs/4.2/security#manually
I'm trying to setup routes for my Symfony2 single page app and I'm not sure how to go about it correctly without it feeling super hacky.
Here is what I need it to do and how I've attempted to set it up:
When Authenticated
Any route requesting application/jsonshould hit the routes they have been setup for as usual.
Any route that is entered not requesting application/json should load a controller that renders a twig file containing all the JS for my single page app.
Any static resource that doesn't exist and ends looking for a symfony route eg [.js, .css, .jpeg, etc] should return 404.
When NOT Authenticated
Anything requesting application/json should return 403
Anything NOT requesting application/json should return to the login page
Here is what i've attempted so far:
Setup routes with the FOSRestBundle for each service
Setup a listener that returns the base controller html if the request isn't application/json
if (!in_array('application/json', $request->getAcceptableContentTypes())) {
$fakeRequest = $event->getRequest()->duplicate(
null,
null,
array('_controller' => 'HvHDashboardBundle:Dashboard:index')
);
$controller = $this->resolver->getController($fakeRequest);
$event->setController($controller);
}
Setup a bunch of 'catch all' routes to fake a 404 if the static resource doesn't exist.
# routing.yml
# Catch any files that are meant to be their own static resource and return 404
catch_all_fail:
pattern: /{uri}.{_format}
defaults: { _controller: MyBundle:Dashboard:return404 }
requirements:
_format: js|hbs|css|jpg|gif|jpeg|png
Issues
This approach feels like a massive hack, and is not how the Symfony routing system is intended to work
The base controller page is returned even if you aren't authenticated because the type listener is being hit before the security context and forcing that controller to render.
Question:
How do other solve this issue with routing and single page apps with Symfony where they initially need to render HTML with twig, then JS takes over and requests JSON?
Only make an API, no static pages at all. Trust me, I recently did a moderate sized API with Symfony and that's the way to go. It will simplify your backend security a lot, if you do not mix the API with static pages. Ofcourse you can still have static pages, if you want to have some sort of Landing page or something. but try not to mix them with the main app.
Even for login, do not make a static page, but instead have an api route that will validate username/password and return the user the auth token in response. One user can have multiple tokens for example (can be logged in at multiple locations), and the token is sent in the request headers everytime.
If the token is validated ok, symfony will know which user it belongs, so you will know the 'User'. If no token is present, it should return "Not Authenticated", and if token is invalid also something like that or 'Bad request'.
One thing that I had to do when doing with APIs is that I had to write a request listener to accept JSON content and transform it into request object, so I could access data with $request->request.
If you have any questions, let me know in comment and I can help.
As far as routing is concerned, follow the REST rules and you will be good to go.
I'm just new to Laravel but I immediately fell in love with it. As a not so super experienced php developer I do find the official documentation, although very expansive, somewhat complicated to use and find everything I need.
My question is about the Routing component. As the documentation states you can assign a route to a controller with the Route::controller method. So if I want a Blog controller for all /blog/ routes I assign it like this:
Route::controller('blog', 'BlogController');
So then if I'd like to acces all my blog posts I acces the the getIndex method by www.foo.com/blog or www.foo.com/blog/index
But let's say I'd like to be able to display categories via a getCategory method. My url would look like www.foo.com/blog/category and if, for example, I want to get the news category from the DB by slug, I'd like to use: www.foo.com/blog/category/news as the URI.
My question now is, how do I pass the slug to the url and access it in the getCategory method? Do I need specify it via Route::get('blog/category/{slug}', 'BlogController#getCategory') or is there a way to use Route::controller('blog', 'BlogController') and to send and acces parameters from the URL in the getCategory method?
I already tried to find it via google and in the official documentation, but I couldn't find a crystal clear answer to this problem...
You can simply add parameters to your getCategory method:
public function getCategory($category) {
die($category);
}
If you initialize it to null in the parameter list, it becomes optional. Alternatively, you can always pull parameters from the Input object but they would need to be passed in querystring format:
$category = Input::get('category');
With that said, I'd caution against using the Controller route. It's handy and mimics traditional MVC frameworks, but I believe it's planned to be deprecated -- and honestly, you miss out on some pretty flexible features.
using Route::controller('blog', 'BlogController'); allows you to define a single route to handle every action in a controller using REST naming conventions.then you have to add methods to your controller, prefixed with the HTTP verb they respond to. That means if you have a method called getIndex() it will be executed when there is a GET request to the url "yoursite.com/blog".
To handle POST requests to the same url add a method prefixed with post(ex: postComment()) and so on for other http verbs PUT, PATCH and DELETE.
I think you want something more customized, so you can use a resource controller:
Route::resource('blog', 'BlogController');
This will generate some RESTful routes around the blog resource, run php artisan routes in your project folder to see the generated routes, it should be something like this:
Verb Path Action Route Name
GET /blog index blog.index
GET /blog/create create blog.create
POST /blog store blog.store
GET /blog/{blog} show blog.show
GET /blog/{blog}/edit edit blog.edit
PUT/PATCH /blog/{blog} update blog.update
DELETE /blog/{blog} destroy blog.destroy
in the action column are the functions that you should have in the controller.
If you want to define more routes you can simply do it with Route::get or Route::post in the routes.php file
I hope this will make it more clear for you, enjoy routing with Laravel!!!