در حال بارگذاری ...

Review Refactor Bug0:06

All right, welcome back. So we're about to move on to authorization using gates, but real quick before we get there, gimme two minutes. Uh, in the last episode, we did some refactoring to a dedicated action class, but I should probably do a quick review just to make sure I didn't screw anything up. So with that in mind, I'm gonna use Code Rabbit again. I've run the review. Here's the action, uh, notes. And I can see right here we have a critical one

I've run the review. Here's the action, uh, notes. And I can see right here we have a critical one or oh, uh, undefined variable in transaction closure. The closure references attributes right here, I already see it, but it's not included and they use clause. Okay? So yeah, this is, this is why it's so incredibly important to one, have a good test suite, but two, have some kind of review system in place to pick up on errors you might have, uh, introduced. So, yes, in this case, I, I expected attributes

to pick up on errors you might have, uh, introduced. So, yes, in this case, I, I expected attributes to be available, but I didn't do this, which means no matter what, this is always going to evaluate to an NTRA and no steps will be inserted. Okay? So now you might be thinking, well, Jeff, you ran your test suite and it passed. So why, why did it, why didn't it fail? Now, it didn't fail because this ran, but no steps were inserted

Add Missing Test1:13

Now, it didn't fail because this ran, but no steps were inserted and we don't have a test to ensure that the steps were inserted, which means if I just removed this entirely, it would still pass, which is a problem. So let's fix that really quickly. Let's go into create idea test. And yet, right here, let's take these and do a new one. It is called New Step.

And yet, right here, let's take these and do a new one. It is called New Step. Do a thing, submit new step button, and then let's do it twice. Do another thing and click it. Okay, so now our assertion is going to be that after the idea is created, we should have, um, two steps. So let's do this. This is our idea, and then I'm gonna say, expect idea steps to have count of two.

and then I'm gonna say, expect idea steps to have count of two. Alright, so now if we give that a run, it fails and this is what we want. We have now confirmed that things are not working, uh, the way we'd expect. Okay? So at this point, we return to our action, we fix the bug, we rerun the tests, and it returns green. All right? That's why we do this.

Introduce Authorization2:22

and it returns green. All right? That's why we do this. That's why we write tests and that's why we have a review system in place. Cool. Okay, so now we can move on to this episode's lesson where we talk about, um, authorization. So let's go into idea controller. And we have a couple issues right now. So notice right here, when we call store and we run this action, it will accept the current user.

So notice right here, when we call store and we run this action, it will accept the current user. And whenever you're operating with the current user, authorization is fairly safe. 'cause it's always based on the current user. But you'll also notice things like edits or update or destroy. And like you see here, well, if you make a request to this endpoint, even if you did not create the idea itself, you now have power to delete the idea.

to this endpoint, even if you did not create the idea itself, you now have power to delete the idea. And that's not good. So that's why we should always defer to authorization. And as we've learned in the first section of this course, we can either use gate authorize, uh, directly within the controller action, or we can reach for it as a middleware. So let's start with the controller approach. First up, you'll remember when we generated our model,

Create Policy Rule3:27

So let's start with the controller approach. First up, you'll remember when we generated our model, it also included a policy called Idea policy. And it just gave us a, a simple scaffolding here. Alternatively, you can make this on your own by saying PHP Artisan make policy. And then you would write idea policy. Cool. This is the policy, this is the authorization policy for an idea. And you'll notice it gives you a bunch,

policy for an idea. And you'll notice it gives you a bunch, because frequently the rules are different. Whether you can, uh, view something is different from whether you can create something and potentially whether you can create is different from whether you can delete. However, in our case, it's so incredibly simple. I I don't need all of these. I can make it pretty basic. Let's do this. Let's rename this to what can the user

I I don't need all of these. I can make it pretty basic. Let's do this. Let's rename this to what can the user modify the idea? Uh, can they update even something like work with that would be fine too. Is the user authorized to work with, uh, this idea? Um, this would be, this would be great, no problem. And you have full control here. Alright, so what's our logic? Well accept the idea

Alright, so what's our logic? Well accept the idea and then I'm going to return whether or not the idea, uh, user is the current user. So remember, this is always the current user and idea. User will refer to the user who created the idea. So let's make sure again, the user who created the idea is the current user. And if those match, then you are authorized to make this change.

Authorize in Controller4:58

And if those match, then you are authorized to make this change. Cool. Alright, so now we have a policy, let's now return to idea controller and let's do one of the other ones. Like, how about show? Let's just test this out at the moment. You can show any idea here. And the only, uh, rule we have at the moment is you have to be signed in. But if you're signed in, you could still view the idea

rule we have at the moment is you have to be signed in. But if you're signed in, you could still view the idea for somebody, um, who is not you. So again, this is why authorization is so incredibly vital and why so many projects to be honest. Um, don't do a good job of this, especially smaller projects. Okay? I me show you this in real time actually here I'm logged in as myself and let's view an idea. But if we change it to an idea that we didn't create,

here I'm logged in as myself and let's view an idea. But if we change it to an idea that we didn't create, for example, one was created by somebody else, well, I can view it even though again, this isn't listed anywhere here. I didn't create that idea. It's somebody else's idea. Okay? So again, big, big problem, we're now gonna fix it. Let's say gate pull in the facade. I'm going to authorize whether or not you can work with this idea.

I'm going to authorize whether or not you can work with this idea. Yeah. And again, name it whatever you want. If you don't like work with, then update or modify. But now you'll see if I switch back and give this a refresh, I get a 4 0 3 that stands for forbidden. You are forbidden from accessing this page. But if I try to access, for example, uh, one of the ones that I created, well, of course

Route Middleware Authorization6:29

But if I try to access, for example, uh, one of the ones that I created, well, of course I am authorized, so I don't get that. So it's perfect. This is what we want. Now remember, uh, you have the option of performing your authorization within your controller action, or you can do it as part of the route like this. Let's say right here, I'll just split this up. Uh, and by the way, some people like to do this. They'll put each of them on their own line anyways.

Uh, and by the way, some people like to do this. They'll put each of them on their own line anyways. Now I can say, yes, you have to be signed in and I can use an array syntax here. However, you also have to be authorized. So I can say, can colon work with comma? The idea? Yeah, it's a little funky and I'll show you a nicer way to write this, but this would be the middleware approach. So now, yeah, if I came back

but this would be the middleware approach. So now, yeah, if I came back and we went to ideas slash one, we still get a, uh, 4 0 3. But if I try to view my own, that works, uh, so yeah, that's an option, but it's a little confusing to me. Can is the name of the middleware work with is the ability, and then idea refers to the route parameter that would be resolved and passed. Um, so alternatively, if you want, you can use a can method, and this is still deferring to the middleware.

Um, so alternatively, if you want, you can use a can method, and this is still deferring to the middleware. Again, it's just like sugar. So can you work with ability, name the given idea? So yeah, this is really the only confusing part. We're not passing the string idea. We are passing the route parameter name that will be resolved accordingly. And so then when the policy is triggered, yeah,

that will be resolved accordingly. And so then when the policy is triggered, yeah, we're not passing the string idea, we're passing the resolved idea. So if we come back, refresh, yes, I can access this, but if I go to a different one, I cannot access it. And yeah, this is what we want. So you, you're now wondering, well, which one do I do, do I handle, uh, authorization at the route level or at the controller level?

do I handle, uh, authorization at the route level or at the controller level? And the answer is, I don't really have an answer for you. It's whatever feels best to you. Do you like to put it here? Does it make sense you do your au middleware here? Uh, is that good or do you really wanna see it directly within your controller as we've done here? Uh, to to reiterate, there's no real right or wrong. It's just what you or your team wanna do. Okay? So with that in mind, uh,

Write Authorization Tests8:42

It's just what you or your team wanna do. Okay? So with that in mind, uh, I'm just gonna do it at the controller level. So yeah, what you might do is you run your authorization, uh, where relevant, when you update it and when you destroy it. Okay? So now I'll show you some tests we can write for this, uh, within the test browser folder. Let's add one called show idea test. So let's write a test. Maybe I'll show you two. Uh, we'll say, must be signed in

Let's add one called show idea test. So let's write a test. Maybe I'll show you two. Uh, we'll say, must be signed in to view an idea. All right? So you can write it in this syntax or you can also use an IT function. It's an alias, it does the same thing, but it allows you to write and structure your sentence a little differently. Like it requires authentication if you wanna keep it a little more simple.

Like it requires authentication if you wanna keep it a little more simple. So for example, you could say, well, if we had an idea like this and we try to visit that ideas page, well, I could say I could either use visit or simply get, uh, if I try to get route idea show, then that should be forbidden, right? It's disallowed. So I could say assert forbidden. So if I give that a run it fail, oh,

It's disallowed. So I could say assert forbidden. So if I give that a run it fail, oh, I'm sorry, it's not forbidden. It, uh, requires authentication, which means we should be redirected, uh, to the route login. Sorry, yeah, if you're not signed in, the very first step is you need to be logged in. So that should pass. But next we could say it requires, um, authorization. Or you could say it disallows accessing an idea you

it requires, um, authorization. Or you could say it disallows accessing an idea you did not create, right? Structure these however you want. Okay, so let's say we have a user And we sign that user in. So we say this acting as user. Next we have an idea that the user did not create, but if the user tries to visit that page for the idea, well now they're signed in.

but if the user tries to visit that page for the idea, well now they're signed in. So they've, they've achieved step one of our checks. Step two is, well, did you create that idea? No, you didn't. In which case, assert forbidden. So we give that one a run and it returns green because we added support for that. So if you ever wanna make sure, is this actually working the way I expect? Then you come back, comment it out, run it again,

is this actually working the way I expect? Then you come back, comment it out, run it again, it's gonna fail of course, because we didn't get a 4 0 3, we got a 200 response. So they were able to access it, return it, run it, and now we are testing authentication and authorization for an idea. And yes, uh, realistically you should do this for all of them. So what you can do, like I said,

you should do this for all of them. So what you can do, like I said, everyone structures things a little bit differently. Um, you could have an idea folder and then you just have a different test for each thing you can do with an idea. Uh, and often these will correspond to action classes. So notice that I have an action called Create Idea, and then we have a browser test called Create Idea Test. We, there, there's a one-to-one link

and then we have a browser test called Create Idea Test. We, there, there's a one-to-one link between them, which is really cool. Uh, alternatively though, if you just want an idea test that houses all the different, um, things you wanna check, that's okay too. It'll eventually get messy, but it's okay to start. Alright, so I think this is enough to get the, the general idea across. If you're working along, make sure you implement some

the general idea across. If you're working along, make sure you implement some of these remaining tests on your own. Otherwise, in the next episode, let's keep going.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟