Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
FREELessons:14Length:2.8 hours

Next lesson playing in 5 seconds

  • Overview
  • Transcript

3.5 Security and Authorization

We need to limit who can post and edit messages. ASP.NET makes it easy to do authorization and authentication, and in this lesson I'll show you how.

3.5 Security and Authorization

When it comes to creating and editing messages, we have just about everything that we need. In fact, the only things that we lack is actually sorting the data, and then adding security. Because we don't want just anybody to be able to create and edit messages. We want to limit that capability To registered users. And even then we want to limit who can edit a message. We want to limit that so that only an author can edit their own messages. So there's different layers of security that we need to add to our application. But first, we need to address our message class. Because it's not good enough to have just the title and the content. We some way of identifying a unique message, so we need an ID. Now we can approach the ID in several different ways.The most common is Is with an autoincrementing number, so we can just create an int property called id. We could also use guids if we wanted to do that, but we'll just stick with integers because those are easier to work with. The next thing we need to do is be able to relate a message with a user. So we need to store the user's ID. And this value can change depending upon our application. Now, this application uses identity for user management. And by default, the identity user Has an ID that is a string. So, we can create a string property called user ID. Now, if your application uses identity but you're not really sure of the type of the ID, I can show you how to figure that out. The user class for this application is called application user. And it is inside of the Identity Models file. So, there it is. Now we could come in here, and we could customize this if we wanted to. But we're going to leave it alone. And you can see that this application user inherits from IdentityUser. Now this is the user that most systems are going to inherit from. And so, if you see this, then you know that the idea is probably going to be a string. However, you can be sure by looking at the definition of this identity user class. So you can right-click on the class name, you can go to definition And then you can see the metadata for this class. Now here we only see two constructors, I-D fault and then one for the user name. But you can see that this identity user also inherits from an identity user of string. While its this type parameter. That is the type of the id. So if we look at the definition of this identity user of string class, we can see that we have an id property that is of type TKey. So that's how you can figure out the type of an id for An identity user. In most cases it will probably be a string, but it never hurts to investigate and see what exactly that you are working with. So we have the ID, we have the user ID. The next thing we would like to have Is the date and time that a message was created so lets go ahead and create a property of date time add lets just call it created. Now we could also add some tracking here so that whenever a message is updated then we can have the date it was updated, but we aren't going to go into that much detail. For our purposes, this is going to be fine. And so now we just need to store our message objects. Now normally we would go back to our identity models file. And you can see that there's this application DB context, and we could add a property that is of type DB set of message. And we can call it messages. And this would serve as our database table for storing our messages. Now the problem here is that we are working with beta software. It's Entity Framework 7 beta 4. And the problem with beta software is that, well it's beta. It has bugs, and in order to get this to work, we would have to migrate our database. That's how you Make changes to an existing database using entity framework. If you add columns or add a different model, in this case we would be adding a container for our message objects, then we would need to migrate the database And migrations aren't working. I can not get migrations to work, and other people can not get migrations to work. So we aren't going to be able to use entity framework in order to store our messages. We can still use it to store our users because that's already set up. So instead, I wrote a quick little in memory data store for our messages. It's inside of the Data folder and it's simply called MessageRepository. In some of this class we have a collection of messages, and this is going to serve as our data store. We will manipulate this collection by adding new messages to it and changing the messages inside of it. And you can see that there are several variables that we have here. Now the first is IdCount so that's for keeping track of the next Id, and then we have two values for UserIds. We're going to create two users in our system. We will get their UserIds. And plug them in here, so that we can actually have some relation between our messages and the users that created them. And then there's this static constructor that populates the messages collection with a few messages, and you can see that Those are there, each have an Id, a UserId, a created value message title, and message content. Now we have three methods, one for retrieving a message by an Id, although, we should probably add another for retrieving all of them. So, let's go ahead and do that. This is going to return an IEnumerable. Of message, and we'll just call it GetAll. We don't need to accept anything because, well, this is getting all the messages, and we will simply return messages, and call the ToArray extension method. And that will give us all of our message. So we have four. We have one for retrieving all of the messages, one for getting an individual message by ID, and then we have this update method. That that doesn't do anything. The reason being, because whenever we update a message, we are going to retrieve it from the data store first. And since we are working with the actual object that's within our messages collection, We don't need to do anything inside of this method, so that's why that has nothing. And there's this method called Add, where we will add a message to our collection. So that's how we're going to be playing with a data store. Within this application. So we can close that, let's close our identity models, because we aren't going to do anything there. And let's go ahead and pop over to our controller so that we can start adding the code for creating and editing messages. And let's create our repository as a private class variable. So private read only, Message repository. We need a using statement for our data name space and let's just call it _messages. Now the reason why I'm doing this here at the class level is because we're going to need the repository. In just about every method on this controller. The index is going to eventually display the messages, so we need the repository. Any time that we create, we need the repository. Any time we add it, we need it as well. So it makes sense to create this at the class level, instead of inside of each individual method. There's also different schools of thought as to how you should interact with your data access layer from inside of your controller. Some people are fine doing that. Other people like to have a service layer. In between the controller and the data access layer. And that's what I typically go with. I have a service layer that does whatever it needs to do with the data access layer. The reason being because it's a nice separation of concerns but it also makes the controller Nice and clean. However, for this application, we are going to keep things simple, and we're just going to use the repository directly inside of the controller. So let's start with the create method. Whenever we submit the create form, we want to, first of all, get our model We want to validate it, which is what we are doing, so we no longer need that todo, and then we want to store that within our data store. Now, we don't have everything that we need just yet. We first of all need the date for this message, so we can say model dot created Equals date time dot now. We also need the user ID. So we could do model dot user ID. And we can get the user ID with a property on controller called user. This is how we access the user that is currently logged in. Now, there is an extension method that we can use that makes it easy to get the user ID. And we need to add a using statement for system.security.claims. This is going to give us a method called, get user ID, I believe. So we can do get user ID. And that will give us the user ID of the user. And then we just want to create that message in our data stores. So we will say _messages.Add, and then we will pass in our newly created message. And that's all that we need to do inside of the create method, so let's move on to the edit method for get Requests. Now we don't want to create this message object. Instead we want to retrieve it from our repository. So let's do var message = _messages, and we will use the GetBy method And pass in the id. Now, we are checking if message == null. Then, we return that it is not found. But we should also check to see if the messages user id is equal to the logged in users id. So, let's do if (message The user ID is not equal to user dot [iii] user ID. Then, the user is not authorized for this resource, so we can return http. Unauthorized. And then, if everything else is fine, then we pass the message on to the view. And then we want to do essentially the same thing inside of the edit method for post requests. So let's first of all retrieve the message from the data store. We check if message is equal to null. If it is, then once again, it's not found. We should also check the UserId before we do any ModelState checking. So let's copy and paste that code. And then we will check the ModelState. If that's not valid, we return the view. But if everything else is okay, then we update the title and And the content and then we call the update method on our repository. Now we know that that's not necessary because we are actually changing those values right here and since that is stored in memory we have already done everything we need to do. But for the sake of completeness Then, we are going to call the update method, and pass in that message object. We have one layer of security, ensuring that the message's user is the only one that is editing that message. The next thing that we need to do is ensure that a user is logged in. In order to access really anything in this controller. The only thing that we want anonymous access to, is the index. Now we can approach this in two different ways. The first is to add an attribute called Authorize. To each of the methods that we want to protect. Now this authorized attribute resides within Microsoft AspNet Authorization, so we need to add that to our using statement. But then we can apply this authorize attribute to Each of the create methods and each of the edit methods. So that's the first way, the second way is to apply the authorize attribute at the class level. So we can come up here to the controller and we can say that, okay. Everything inside of this message controller is protected. The user has to log in before they can access them. But that's a slight little problem with the index, because anybody should be able to view the messages we just want to protect create And editing messages. So in this case, we can add another attribute to the Index action method. And that is called AllowAnoymous, so that a user still has to be logged in to access anything else on the controller but they do not have to be logged in to access the index action method. Well now we need to create two users so that we can get their user IDs and use them inside of the repository so that we can relate a user User with their messages. And we're going to create these users with the registration link in our application. So just start it up, go to register, and we need two things. We need an email address, which does not have to be a working email address, this first email address is going to be foo@foo.com and then we need a password. Now, There are some complexity rules for the password. It needs to have an uppercase, lowercase, some numeric value, and a special character. So that is the password that I'm going to use. I'm just going to copy that so that I can paste it Every place that I need to. And we will create that first user. You can see that it automatically logs the user in, so we see that foo@foo.com. And let's log off, let's register another user. This can be bar atbar.com. And we'll use the same password because, well, it's easy to do. So we've just created our two new users. Now we need to get their user IDs. So we need to go to view And the SQL server object explorer. And this is going to allow us to look at the local db instance. And it has a database that is used for this application. Now you can see that there are actually three local db instances here. What we want is this Microsoft SQL local db. I think this is what we need. I can easily find out by drilling down to the Databases, and here we see a database called aspnet5-SoundBoard and then a GUID. So this is the database that was created, and it's going to have the data that we need. So we just want to drill down to our Tables. We want to look inside of this AspNetUsers, and we can right-click And we can view the data. And this is going to show us the information for our users. So here we have the ID column. Although that’s kind of strange that it's not at the beginning Looking at this, all of the columns are in alphabetical order, so that is really the first time I've ever seen that. Mind you, we want to devalue the ID and this is a good value essentially, and we just want to take these values and go to our repository class and paste them in. So lets go to the data folder, message repository. And then I have these two variables again. UserIdOne, we will paste in that value, and then we can return to our data. We can copy the ID of the other user, and paste that in for user two. It doesn't matter which user is one or two in this code. All we want is a user to be UserIdOne, and the other user to be UserIdTwo. And so now we have just about everything ready to finish this application. We have the create and edit functionality complete, we just now need to display all of our messages and we will get started with that in the next lesson.

Back to the top