Monday, August 4, 2014

ASP.NET MVC 5 Authorization instead of Web Configuration site

So! I've been searching on the internet what happend with ASP.NET Website Configuration page? You know the...Create Users, Manage Roles, Set Rules page that you had in Visual Studio 2010? Well in the version before Visual Studio 2013 Express actually, since it is no longer there in the version of 2013. I mean of this website configuration page if I am not making my self clear already.

But for some REASON it doesn't exist anymore in Visual Studio 2013. I was searching for like 5 hours today can it be back? And actually it can. BUT! It took me about 5+ hours to realize that the REASON it is not there is - because it's old. Even on Microsoft forums no body is talking about it, because it's not wanted anymore. I was like eager to have the Web Configuration site back!! I knew how to use it and it was good. I actually did found together with my brother a workaround how to make it work in Visual Studio 2013, but something gave me this feel that , it shouldn't be in MVC 5. Yet I am not even sure if that workaround is doing what it should.

But then I read on the one of the Microsoft's ASP.NET tutorials, that Authorization in MVC 5 is there for, simple fact, that people want more to use their Facebook, Twitter, Google account's to log in on a specific page and leave comments. And then it gave me more sense of what is the application of MVC 5 in Visual Studio 2013 about. Because when you create new project in the Visual Studio 2013 Express you can check out that they offer you in Authorization configuration which you can set and there it says:

 "For applications that store user profiles in SQL Server database. Users can register, or sign in using their existing account for Facebook, Twitter, Google, Microsoft or another provider."

And that's what your authorization for the appliaction is. That's what I chose because mainly I needed a registration on the site, then there are codes you can write in the authorization classes to allow Facebook, Twitter and other account to log on to your app but that's not what I am writting this post about.

I wanted to show you how the authorization can be done for a specific page using, the built-in Registration and LogIn buttons you get with the Bootstrap theme of the new project in Visual Studio 2013. I hope you have main understanding of Controlers, Models and Views for I'll try to make this short. I'll show you just the main principle of authorization that I belive you can achieve a lot later with it. So here it goes:

1. In Visual Studio 2013 Express for Web, create new ASP.NET Web Application project and select MVC, check in Change Authentication button if the Individual User Accounts is selected, so you make sure you have authentication that I mentioned previously and make sure NoAuthentication is NOT selected. Give a name for app whatever you wish, for me is just WebApplication4.

Visual Studio 2013 Create New Project



So you have in Solution Explorer standard folders, including Controllers, Models, Views. If you go to Controllers and choose HomeController.cs file, you'll see on the main screen, three functions called Index About and Contact. I chose About method just because thats the first thing that felt to me non-important to experiment with. So one line of code I came across on ASP.NET official tutorials site is the following one:

[Authorize(Roles = "Administrator")]

However the same tutorial used I think MVC 3 in Visual Studio 2010? I am not sure I can't tell but the interface is obviously older since you had that Globe icon where you opened Web Configuration site in the Solution Explorer. But again, that's older version of Visual Studio, so how this code that just have been written can work for me in Visual Studio 2013 Express when I do not have any Roles, nor I have no idea where my registered Users are being saved?! There is no Configuration site?! The hell!? Luckly OOP (Object Oriented Programing) is a handy thing to know, and I think probably because of it I managed to figure this thing out.

So let's first register one user on our site. You can comment out the code [Authorize] if you have written it already:

2. Do a Rebuild of your appliaction in the Build menu and launch your application with Start Debugging. Once it is started go into Register and create an account. Enter the mail whatever you wish, I'll use "dovahkin@dragonborn.com" because its epic name for epic unexisting fictional epical mail domain. And password requires to have one uppercase letter and one non letter or non digit character so I'll use something like - Dovah12#. You can write in whatever, just make a registration.

Register new user


Once you have done that succesfully you should see in the top-right corner saying "Hello registered_email". So the first question that came to my mind after doing that is "Okey so can I use that [Authorization] code with just this user I registered? Can I restrict others for that About page/method and just not this user?" So that's what I did:

3. Go back to Visual Studio 2013. Go to Controllers folder in Solution Explorer, then HomeController and above About method/fuction write:

[Authorize(Users="dovahkin@dragonborn.com")] - just instead of my registered e-mail you write the one you have.

Now there is few things I must point out. This Authorize code, when written above functions/methods are something you use to customize that specific method/function. I think they are called code snippets but I am not sure, I just understood it as a customization for a functions in MVC. Now this is where my knowledge of OOP has come to the rescue! You can notice that the Authorize is written just like a class, right?

Authorize and About method


So what I tought then, since Internet became of no use, is to check what does that class do. If you right click exactly on the Authorize , while nothing else is selected, you will see option Go to Definition or u can just postion blinking indicator on it and press F12.

Go to Definition of the class

I am not going to explain what is every attribute in the definition of the AuthorizeAttribute class doing, it will make this post WAY TOO LONG. I will just say that because of reading what every of those options are doing, I came to conclusion that there is a Users atribute that we have used already, and then there is Roles and TypeId attributes. So I had to ask myself "But where are the Roles!? Where are the Users!? Nothing ever allowed me to create a Role, when there is no freaking Web Configuration site and on the registration page there is no option to choose a role !? Uuurghh!!" Well I didn't ask my self with that agony but it's what I tought. So it had to be in some storage, right? Storage...hmm...storage...that sound's familiar...Database! But where?!

If you look to the Solution Explorer of your project, there is that folder saying App_Data but it's empty. If you look on the top of Solution Explorer there are this icons, and one of them is saying "Show all files":

Show All Files
If you click that you will notice that you can expand now your App_Data, and you can see a file saying probably something like aspnet - name_of_webappliaction - 1021049150105105.mdf. If that's so that is the database. Do a double click on it and you will be switched to a Server Explorer. As you can see, if you ever used SQL Server this is pretty much like it. Why is there? Because MVC is set to make it so. Most of the Begining with MVC tutorials in the internet will show you how to create databases and use them, for now lets open the Tables folder in our Database.

Database Table where users are being registered

As you can see, this tables are where the registered users are being stored. So now it makes sense when we wrote a code saying [Authorize(Users="dovahkin@dragonborn.com)] it worked because Users table is there and it's called AspNetUsers. You can right-click on it and select Show Table Data. You will see your registered user just like so:

UsersTable with registered user

Now we can see that the registered users are stored in a known place (database) and we can know a bit more about them. If you would test your application now and go to About page you will see it requires you to log in because we wrote the code [Authorize(Users="dovahkin@dragonborn.com")] where we restricted that About page to allow ONLY User with specific email to be able to access it. You could register another account with diffrent email and password and it won't be able to access About page because we specified only ONE user and that is the user with "dovahkin@dragonborn.com" email.

So now there is a question:  "Okey but what if I have MANY users who are allowed to enter About page and MANY users who are not?!" If you go back to Server Explorer you will notice there is AspNetRoles and AspNetUserRoles, tables. Both are empty as there is no place on our page to fill them. And we need to fill them both so we make a "connection" between users and roles so that we set which role matches a certain user. Hope this is not too confusing.

I won't go into creating a whole page and fields to fill them, it is already too long post so we have to fill those two tables manually. I hope you have a bit of knolwedge for SQL so this is what we will do:


  • Register another user in on the web-page (launch app and register user)
  • For AspNetRoles table in our database do a New Query and insert two values both are strings so I've added - 001(id) for Administrator and 002(id) for User
  • For AspNetUserRoles you have to insert UserId which you can find in AspNetUsers table and RoleId which you can find in AspNetRoles table. It is important for you to remember which user is what. One have to be Administrator and one have to be User.

You have a bit to check things back and forth, move trough tabs a bit more, it helps a lot if you have dual-screen. But to insert values into tables, a quick reminder it goes: 

INSERT INTO tableName VALUES ('string', 'string')

Once you've connected your Tables , you should have AspNetUserRoles table looking something like this:

UsersRole table 


Main goal with this table is that you connect desired users to have role of Administrator and role of User. Now all that's left is to change the [Authorization] code to restrict Role instead of user. So we write following:

[Authorize(Role="Administrator")]


Rebuild your project, Start debugging or without debugging, which ever you prefer, and lets try accessing to About page again. It should ask of you to LogIn again. If you log with your Administrator registered account that you connected in the database table AspNetUserRoles, for me it is dovahkin, you should be able to continue to the About page and read the "Your application descripition page." This means that the restriction for the About page for this account is working, meaning you can access to the About page because the Role of the, in my case dovahkin@dragonborn.com user is Administartor. Try doing the same with 2nd account you registered. If everything have been done correctly, it will ask you again to LogIn, meaning that the Role of the 2nd registered account is not allowed to acces this About page.


Conclusions

This is just the basics of how you can set authorization for roles work. Normally you would want to create on the registration page a field to check, which role is the registered user going to be, but then again if you would want to set that option you would also have to set it for a Administration roles, because it wouldn't really make sense that EVERYONE can register as Administrator, right? I really hope I did not bore you to death with this post, I really got excited for figuring this out, I was a bit in doubt that because of not having a Website Configuration page things are much more complicated, but all it took is one line of code...basically...well it really looks like that. But if you ask me, I think this give much more flexiblity for developers.  There is right now tons of things coming to my mind to try out. I hope you found this post usefull, I hope I explained it at least to a "understandable" level. If there is any question regarding this post or anything about it that might not work, do not hasitate to ask I'll gladly help. Have a nice day/evening/night , stay calm and ...

...link.