关于ASP.NET MVC 5 的一种简单的身份验证方式:FormsAuthentication.Authenticate

在ASP.NET MVC 5中,身份验证分别有三种方式。分别为使用FormsAuthentication、MemberShip和Identity进行验证。

(PS:本系列的逻辑代码请勿直接用于生产,请自己多加一层抽象后再投入使用)

为了展示这三种方式,我们先新建一个MVC项目。

为了方便,我们创建一个类用来验证身份。

 

    public class AccountHelper
    {
        [Required]
        public string UserName { get; set; }
        [Required]
        public string Password { get; set; }
    }

方式一:FormsAuthentication

在使用任何一种验证方法之前,我们需要创建一个视图用以进行登录,然后在这个视图中创建一个form用以提交数据

        public ActionResult Login()
        {
            return View();
        }  

视图代码:

@model Authority.Models.AccountHelper

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>
<p>Please log in to access the administration area:</p>
@using (Html.BeginForm())
{
    @Html.ValidationSummary()
    <div class="form-group">
        <label>User name</label>
        @Html.TextBoxFor(m => m.UserName, new { @class = "form-control" })
    </div>
    <div class="form-group">
        <label>Password</label>
        @Html.TextBoxFor(m => m.Password, new { @class = "form-control" })
    </div>
    <input type="submit" value="Log In" class="btn-primary" />
}

然后我们需要在Web.config中对验证方式进行配置。

    <authentication mode="Forms">
      <forms loginUrl="~/FormsAuthentication/Login" timeout="2880">
        <credentials passwordFormat="Clear">
          <user name="admin" password="secret" />
        </credentials>
      </forms>
    </authentication>

接着需要创建一个方法用来接收form元素所提交的数据,对数据进行验证并保留Cookie,对验证成功后返回另一个视图。

        [HttpPost]
        public ActionResult Login(AccountHelper helper,string returnUrl)
        {
            if (ModelState.IsValid)
            {
                if (FormsAuthentication.Authenticate(helper.UserName, helper.Password))
                {
                    FormsAuthentication.SetAuthCookie(helper.UserName,false);
                    return Redirect(returnUrl ?? Url.Action("AfterAuthority",helper));
                }
                else
                {
                    ModelState.AddModelError("", "Error account or password");
                    return View();
                }
            }
            return View();
        }

对验证成功后的视图进行简单的定义。

        [Authorize]
        public ActionResult AfterAuthority(AccountHelper helper)
        {
            return View(helper);
        }
@model Authority.Models.AccountHelper

@{
    ViewBag.Title = "AfterAuthority";
}

<h2>AfterAuthority</h2>

<p>Your Username is: @Model.UserName</p>
<p>Your Password is: @Model.Password</p>

其中Login方法的returnUrl 用于未在 Login 处进行验证而直接访问带有 [Authorize] 修饰的视图时,在验证后可返回原来访问的地址。假如我对一个Edit视图(该视图后面会定义)进行访问它会直接返回至Login方法并带有ReturnUrl字段:

 而在验证之后通过returnUrl直接返回至Edit方法。

那么问题来了,要是我想增加更多的用户或者修改现有的账户该怎么办呢?这时候我们就需要对Web.config直接进行修改了。但在这之前我们需要有一个对象用来保存我们现在账户的信息,因此我们需要对Login方法也进行一定的修改:

        static AccountHelper account=new AccountHelper();


        [HttpPost]
        //returnUrl 用于未在 Login 处进行验证而直接访问带有 [Authorize] 修饰的视图时,在验证后可返回原来访问的地址。
        public ActionResult Login(AccountHelper helper,string returnUrl)
        {
            if (ModelState.IsValid)
            {
                if (FormsAuthentication.Authenticate(helper.UserName, helper.Password))
                {
                    account.UserName = helper.UserName;
                    account.Password = helper.Password;
                    FormsAuthentication.SetAuthCookie(helper.UserName,false);
                    return Redirect(returnUrl ?? Url.Action("AfterAuthority",account));
                }
                else
                {
                    ModelState.AddModelError("", "Error account or password");
                    return View();
                }
            }
            return View();
        }

于是,我们可以创建一个用于修改现有账户的视图了。

        [Authorize]
        public ActionResult Edit()
        {
            return View(account);
        }
@model Authority.Models.AccountHelper

@{
    ViewBag.Title = "Edit";
}

<h2>Edit</h2>

<p>Your Password is: @Model.Password</p>

<div>Edit your account</div>
@using (Html.BeginForm())
{
    <div class="form-group">
        <p>Your Username is: @Model.UserName</p>
        <p>Change it to: @Html.EditorFor(m => m.UserName)</p>
        </div>
    <br />

    <div class="form-group">        
        <p>Your Password is: @Model.Password</p>
        <p>Change it to: @Html.EditorFor(m => m.Password)</p>
    </div>
    <input type="submit" value="submit"/>
}
        [HttpPost]
        [Authorize]
        public ActionResult Edit(AccountHelper changedAccount)
        {
            XmlDocument doc=new XmlDocument();
            //获得配置文件的全路径
            string strFileName = AppDomain.CurrentDomain.BaseDirectory+"Web.Config";
            doc.Load(strFileName);
            XmlNodeList nodes = doc.GetElementsByTagName("user");
            for (int i = 0; i < nodes.Count; i++)
            {
                string _name = nodes[i].Attributes["name"]==null?
                    "":nodes[i].Attributes["name"].Value;
                if (_name==account.UserName)
                {
                    nodes[i].Attributes["name"].Value = changedAccount.UserName;
                    nodes[i].Attributes["password"].Value = changedAccount.Password;
            //清除Cookie FormsAuthentication.SignOut();
break; } } //将修改后的 Web.config 进行保存 doc.Save(strFileName); return View("AfterAuthority",changedAccount); }

 

刷新之后:

以修改前的账户登录:

   

至此修改现有账号的任务完成。

而新增账户不过将XML元素的修改改成插入。

        [Authorize]
        public ActionResult Add()
        {
            return View();
        }

        [HttpPost]
        [Authorize]
        public ActionResult Add(AccountHelper newAccount)
        {
            XmlDocument doc = new XmlDocument();
            //获得配置文件的全路径
            string strFileName = AppDomain.CurrentDomain.BaseDirectory + "Web.Config";
            doc.Load(strFileName);
            XmlNodeList nodes = doc.GetElementsByTagName("user");
            XmlNode credentials = nodes[0].ParentNode;
            XmlNode child = nodes[0].Clone();

            child.Attributes["name"].Value = newAccount.UserName;
            child.Attributes["password"].Value = newAccount.Password;
            credentials.AppendChild(child);

            //将修改后的 Web.config 进行保存
            doc.Save(strFileName);

            return View("Create", newAccount);
        }

Add视图:

@model Authority.Models.AccountHelper

@{
    ViewBag.Title = "Add";    
}

<h2>Create Account</h2>
@using (Html.BeginForm())
{
    <div class="form-group">        
        <p>UserName: @Html.EditorFor(m => m.UserName)</p>
        <p>Password: @Html.EditorFor(m => m.Password)</p>
    </div>
    <input type="submit" value="submit"/>
}

Create视图:

@model Authority.Models.AccountHelper

@{
    ViewBag.Title = "Create Success";   
}

<h2>Successfully</h2>

<p>UserName: @Model.UserName</p>
<p>Password: @Model.Password</p>

但是问题又来了,总不能什么人都可以对账户进行修改或增添用户吧,因此我们需要使用自定义特性,通过继承AuthorizeAttribute获得和AuthorizeAttribute同样的效果,通过继承IAuthenticationFilter对账户进行过滤,在此我们限制Add方法只有admin这一账户可以使用:

    public class AdminAccountAttribute : AuthorizeAttribute, IAuthenticationFilter
    {
        public void OnAuthentication(AuthenticationContext filterContext)
        {
            IIdentity identity = filterContext.Principal.Identity;
            if (identity.Name!="admin" || !identity.IsAuthenticated)
            {
                filterContext.Result = new HttpUnauthorizedResult();
            }
        }

        public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
        {
            if (filterContext.Result == null || filterContext.Result is HttpUnauthorizedResult)
            {
                filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary()
                {
                    {"controller","FormsAuthentication" },
                    { "action","Login"},
                    {"returnUrl",filterContext.HttpContext.Request.RawUrl }
                });
            }
        }
    }

然后将该修饰用于Add之上:

        [AdminAccount]
        public ActionResult Add()
        {
            return View();
        }

        [HttpPost]
        [AdminAccount]
        public ActionResult Add(AccountHelper newAccount)
        {

于是我们便只有admin用户可以对Web.config进行增添用户的操作了。

 

通过一个非admin用户访问Add页面,返回Login页面。

通过admin用户访问Add页面则返回Add页面。

至此,一个完整的登录系统达成。如果需要什么额外的逻辑也可自行添加。

但是由于使用FormsAuthentication.Authenticate需要使用Web.config,在Web.config直接对账户和密码进行配置,过于繁琐、不安全且扩展性差,对配置文件进行显式的修改更是增添了风险;同时,如果需要对用户的账号或者密码进行限制我们便需要进行硬编码。该方法早已被弃用,之后ASP.NET推出了Membership.ValidateUser方法解决这一情况,而现在更是有了Identity用来更进一步地提高扩展性。

源代码地址:

https://github.com/NanaseRuri/FormsAuthentication

猜你喜欢

转载自www.cnblogs.com/gokoururi/p/9891071.html