ASP.NET MVC - 用户验证和权限验证

The MVC bits have finally arrived and I’ve spent a while digesting them. I’ve been waiting for the bits to be released to begin working on a side-project, so the first thing I did after downloading them last night was crank it up and start working on a new ASP.NET MVC Web Application project.

Typically, the first thing I do on a new project is set up the authentication/authorization system. For the project I am working on I want to use the ASP.Net Membership system, but most of the Membership controls do not work with the MVC framework because they require postbacks. I spent some time last night building a Security controller and views for Registration and Login that I thought would be worth sharing.

So far I have implemented basic functionality for Register, Login, and Logout. There are three files we will have to create. We will also have to change the routing table. Let’s start with the SecurityController:

    1 public class SecurityController : Controller

    2 {

    3 

    4     [ControllerAction]

    5     public void Login()

    6     {

    7         RenderView("Login");

    8     }

    9 

   10     [ControllerAction]

   11     public void Register()

   12     {

   13         RenderView( "Register" );

   14     }

   15 

   16     [ControllerAction]

   17     public void Logout()

   18     {

   19         FormsAuthentication.SignOut();

   20         Response.Redirect( "/" );

   21     }

   22 

   23     [ControllerAction]

   24     public void Authenticate( string userName, string password, string rememberMe, string returnUrl )

   25     {

   26         // figure out if username and password are correct

   27         if( Membership.ValidateUser( userName, password ) )

   28         {

   29             // everything is good, create an authticket and go

   30             FormsAuthentication.SetAuthCookie( userName, (rememberMe != null) );

   31             Response.Redirect( returnUrl );

   32         }

   33         else

   34         {

   35             // something was wrong, figure out which and pass it into view

   36             if( Membership.GetUser(userName) == null )

   37                 ViewData["ErrorMessage"] = "Incorrect username.";

   38             else

   39                 ViewData["ErrorMessage"] = "Incorrect password.";

   40             RenderView( "Login" );

   41         }

   42     }

   43 

   44     [ControllerAction]

   45     public void CreateUser( string userName, string emailAddress, string password, string returnUrl )

   46     {

   47         try

   48         {

   49             // try to create user and then login that user

   50             if( Membership.CreateUser( userName, password, emailAddress ) == null )

   51                 throw new MembershipCreateUserException( "An unspecified error occurred." );

   52             FormsAuthentication.SetAuthCookie( userName, true );

   53             Response.Redirect( returnUrl );

   54         }

   55         catch( MembershipCreateUserException e )

   56         {

   57             // something went wrong

   58             ViewData["ErrorMessage"] = e.Message;

   59             RenderView("Register");

   60             return;

   61         }

   62     }

   63 

   64 }

 

 

So we have two basic actions methods that only display views (Register and Login) and three action-only methods that have no views (CreateUser, Authenticate, Logout).

I have chosen to not have a logout page, but to instead redirect to the homepage. Switch out ‘Response.Redirect( "/" );’ for ‘RenderView( "Logout" );’ and create a Logout.aspx view if you would like to display a logout message.

Now let’s look at the Login view:

    1 <asp:Content ID="content" ContentPlaceHolderID="MainContentPlaceHolder" runat="server">

    2 

    3     <h2>Login</h2>

    4 

    5     <% if( ViewData["ErrorMessage"] != null ){ %>

    6     <p><% =ViewData["ErrorMessage"] %></p>

    7     <% } %>

    8 

    9     <% using(Html.Form( "Authenticate", "Security" )){ %>

   10     <fieldset>

   11         <legend>Login</legend>

   12         <div><label for="userName">User Name:</label> <% =Html.TextBox( "userName" ) %></div>

   13         <div><label for="password">Password:</label> <% =Html.Password( "password" ) %></div>

   14         <div><label for="rememberMe">Remember Me:</label>

   15             <input type="checkbox" id="rememberMe" name="rememberMe" checked="checked" value="checked" /></div>

   16         <div><% =Html.SubmitButton() %></div>

   17         <% =Html.Hidden( "returnUrl", "/" ) %>

   18     </fieldset>

   19     <% } %>

   20 

   21 </asp:Content>

 

 

The toolkit’s Html.Checkbox(…) method annoys me. More on why in another post. For now I’ve instead just written the html out by hand. You’ll note I’ve also linked the label to the checkbox with JavaScript so that clicking the label toggles the checkbox.

Then the Register view:

    1 <asp:Content ID="content" ContentPlaceHolderID="MainContentPlaceHolder" runat="server">

    2 

    3     <h2>Register</h2>

    4 

    5     <% if( ViewData["ErrorMessage"] != null ){ %>

    6     <p><% =ViewData["ErrorMessage"] %></p>

    7     <% } %>

    8 

    9     <% using(Html.Form( "CreateUser", "Security" )){ %>

   10     <fieldset>

   11         <legend>Register</legend>

   12         <div><label for="userName">User Name:</label> <% =Html.TextBox( "userName" ) %></div>

   13         <div><label for="emailAddress">Email Address:</label> <% =Html.TextBox( "emailAddress" ) %></div>

   14         <div><label for="password">Password:</label> <% =Html.Password( "password" ) %></div>

   15         <div><% =Html.SubmitButton() %></div>

   16         <% =Html.Hidden( "returnUrl", "/" ) %>

   17     </fieldset>

   18     <% } %>

   19 

   20 </asp:Content>

 

 

Another straightforward view. Not much to discuss here.

And finally, let’s add the new routes:

    1 RouteTable.Routes.Add( new Route

    2 {

    3     Url = "Login",

    4     Defaults = new {

    5         controller = "Security",

    6         action = "Login" },

    7     RouteHandler = typeof( MvcRouteHandler )

    8 } );

    9 RouteTable.Routes.Add( new Route

   10 {

   11     Url = "Register",

   12     Defaults = new {

   13         controller = "Security",

   14         action = "Register" },

   15     RouteHandler = typeof( MvcRouteHandler )

   16 } );

 

 

I personally like login to be http://website/login and register to be http://website/register, so that is how I have configured it. The other three actions (Logout, Authenticate, and CreateUser) I access via the default route (ex: /Security/Logout).

That’s it! You should now have a working registration/login system. I’ll leave making it pretty with CSS as an exercise for the reader.

I have included all of the code samples above in the below ZIP file. Just unzip it and place the controller into the Controllers directory, the views into the Views/Security directory (which you will have to create), and copy the code from Routes.txt to the appropriate area of your Global.asax.

MVCMembership_v1.2.zip (2.03 kb)

UPDATE (Dec 11): Johan and Steve Harman were kind enough to point out that I had foolishly set the "remember me" checkbox’s label’s "for" attribute to point to the password field instead of the checkbox itself. I have fixed the code above and provided a new zip file (1.1) for download. Thanks guys!

Update (Dec 19): oVan pointed out a bug in the routing rules defined in the routes.txt file. I have updated the zip file with the correct code. Thanks oVan!

Update (Jan 3): James Nail asked a very good question via a comment: what do you set for the loginUrl and defaultUrl in your web.config? Well James, here is how I’ve setup my web.config…

Assuming we’ll be using forms authentication and securing all pages except login and the homepage, place the following inside the <system.web>element:

    1 <authentication mode="Forms">

    2   <forms loginUrl="/Login" defaultUrl="/" />

    3 </authentication>

    4 <authorization>

    5   <deny users="?" />

    6 </authorization>

 

Then, somewhere outside the <system.web> element add:

    1 <location path="Default.aspx">

    2   <system.web>

    3     <authorization>

    4       <allow users="*" />

    5     </authorization>

    6   </system.web>

    7 </location>

    8 <location path="Security">

    9   <system.web>

   10     <authorization>

   11       <allow users="*" />

   12     </authorization>

   13   </system.web>

   14 </location>

   15 <location path="Login">

   16   <system.web>

   17     <authorization>

   18       <allow users="*" />

   19     </authorization>

   20   </system.web>

   21 </location>

 

Note that this will grant access to all actions within the Security controller. It is also worth pointing out that, dependent on your setup, your CSS and image files may not load unless you also create a location path for their directory and grant all users access like so:

    1 <location path="Content">

    2   <system.web>

    3     <authorization>

    4       <allow users="*" />

    5     </authorization>

    6   </system.web>

    7 </location>

 

I have not updated the zip file with these web.config settings; let me know if anyone would prefer that I add it. I hope this helps some of you!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值