[C#][ASP.NET MVC]實做成員和角色管理

  • 26223
  • 0
  • C#
  • 2010-02-12

[C#][ASP.NET MVC]實做成員和角色管理

在網站安全管理方面,ASP.NET2.0以後提供兩大API(Membership、Role),

幫助開發人員快速建立相關安全管理機制,

而MVC架構下我們當然也可以利用這兩大API實做管理機制,

自己覺得整體開發時間還滿快的(拜MVC所賜XD),這裡記錄一下。

 

Add SystemController

image

公開成員相關屬性


 #region 成員相關屬性

    public class UserAttribute
    {
        public Guid key { get; set; }
        public String Username { get; set; }
        public String Lastlogindate { get; set; }
    }

    public class CreateAttribute : UserAttribute//繼承UserAttribute
    {
        public String Password { get; set; }
        public String Confirmpw { get; set; }
        public String Email { get; set; }
    }

    public class DetailsAttribute : CreateAttribute//繼承CreateAttribute
    {
        public String Comment { get; set; }
        public bool Isapproved { get; set; }
        public String Createdate { get; set; }
        public String Lastactivitydate { get; set; }
        public String Lastlockoutdate { get; set; }
    }

    public class EditAttribute : DetailsAttribute//繼承DetailsAttribute
    {
        public bool IslockedOut { get; set; }
        public String Lastpasswordchangeddate { get; set; }
    }

    #endregion       

 Add SystemRepository

image


public class SystemRepository
    {      
        public List<UserAttribute> GetAllusers()
        {
            List<UserAttribute> users = new List<UserAttribute>();
            foreach (MembershipUser t in Membership.GetAllUsers())
            {
                users.Add(//循環設定公開屬性(UserAttribute class in controller)
                    new UserAttribute
                {
                    key = (Guid)t.ProviderUserKey,
                    Username = t.ToString(),                    
                    Lastlogindate=t.LastLoginDate.ToString("yyyy/MM/dd hh:mm:ss")                    
                });
            }
            return users;
        }

        public List<DetailsAttribute> Detailsusers(Guid key)
        {
            List<DetailsAttribute> Details = new List<DetailsAttribute>();
            var user = Membership.GetUser(key);//依照key取得成員相關資訊
            Details.Add(//設定公開屬性(DetailsAttribute class in controller)
                new DetailsAttribute
                {
                    Username = user.UserName,
                    key = (Guid)user.ProviderUserKey,
                    Email = user.Email,
                    Comment = user.Comment,
                    Isapproved = user.IsApproved,
                    Createdate = user.CreationDate.ToString("yyyy/MM/dd hh:mm:ss"),
                    Lastlogindate = user.LastLoginDate.ToString("yyyy/MM/dd hh:mm:ss"),
                    Lastactivitydate = user.LastActivityDate.ToString("yyyy/MM/dd hh:mm:ss"),
                    Lastlockoutdate = user.LastLockoutDate.ToString("yyyy/MM/dd hh:mm:ss")
                });
            return Details;
        }

        public List<EditAttribute> Editusers(Guid key)
        {
            List<EditAttribute> Edits = new List<EditAttribute>();
            var user = Membership.GetUser(key);//依照key取得成員相關資訊
            Edits.Add(//設定公開屬性(EditAttribute class in controller)
                new EditAttribute
                {
                    Username = user.UserName,
                    key = (Guid)user.ProviderUserKey,
                    Email = user.Email,
                    Comment = user.Comment,
                    Isapproved = user.IsApproved,                    
                    IslockedOut=user.IsLockedOut,                  
                    Createdate=user.CreationDate.ToString("yyyy/MM/dd hh:mm:ss"),
                    Lastpasswordchangeddate = user.LastPasswordChangedDate.ToString("yyyy/MM/dd hh:mm:ss")
                });
            return Edits;
        }     
    }

 Index In Controller


 [NonAction]//新增自訂Url Routing
        protected RedirectToRouteResult RedirectToUserPage( MembershipUser user )
        {
            var rvd = new RouteValueDictionary( new
            {
                controller = ControllerContext.RouteData.Values[ "controller" ],
                action = "Edit",
                key = ( Guid ) user.ProviderUserKey
            } );
            return RedirectToRoute( rvd );
        }

        SystemRepository systemrepository = new SystemRepository();
        
        // GET: /System/
        //[Authorize(Roles = "Administrators")]//屬於Administrators才有權限
        public ActionResult Index()
        {
            ViewData["Roles"] = Roles.GetAllRoles().ToList();
            return View(systemrepository.GetAllusers());//指向systemrepository
        }       

編寫virtual method for role


 #region virtual method for role

        [AcceptVerbs(HttpVerbs.Post)]
        public virtual ActionResult CreateRole(String name)
        {
            Roles.CreateRole(name);//建立新角色
            return RedirectToAction("Index");
        }

        public virtual ActionResult DeleteRole(String name)
        {
            Roles.DeleteRole(name);//刪除角色
            return RedirectToAction("Index");
        }

        public virtual ActionResult AdduserTorole( Guid key, String roleName )
        {
            var user = Membership.GetUser(key);
            Roles.AddUserToRole(user.UserName, roleName);//成員加入特定角色中
            return RedirectToUserPage( user );
        }

        public virtual ActionResult RemoveuserFromrole( Guid key, String roleName )
        {
            var user = Membership.GetUser(key);          
            Roles.RemoveUserFromRole(user.UserName, roleName);//移除特定角色中的成員
            return RedirectToUserPage( user );
        }

        #endregion

 

Add Index View

image

只列出須自行編寫的表現層code


 <fieldset>
    <legend>角色</legend>
    
	<% if( (ViewData["Roles"] as List<String>).Count > 0 ){ %>
	<ul>
	<% foreach( String role in (ViewData["Roles"] as List<String>) ){ %>
		<li>[<% =Html.ActionLink("刪除", "DeleteRole", "System", new { name = Html.Encode(role) }, new { onclick = "return confirm('確定要刪除嗎?')" })%>]
		<% =Html.ActionLink(Html.Encode(role).ToString(), "Role", "System", new { id =Html.Encode(role) }, null)%> 
		</li>
	<% } %>
	</ul>
	<% }else{ %>
	<div>系統中未存在任何角色</div>
	<% } %>
	 <% using (Html.BeginForm("CreateRole","System"))
     {%>	 
	 新角色名稱:<% =Html.TextBox("name")%>	
	 <input type="submit" value="建立" />	
     </fieldset>
     <%} %>

image

新增Guest角色

image image

刪除Guest角色

image image

 

Details In Controller


 public ActionResult Details(Guid key)
        {
            return View(systemrepository.Detailsusers(key));
        }

Add Details View

image

須自行修改Details參數部分


....
.......
........
 <p>
            最後鎖定日期:
            <%= Html.Encode(item.Lastlockoutdate)%>
        </p>
    </fieldset>
    <p>
        <%=Html.ActionLink("Edit", "Edit", new { key = item.key })%> |
        <%=Html.ActionLink("Back to List", "Index")%>
    </p>
    <%} %>

image

 

Create In Controller


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

        //
        // POST: /System/Create

        [AcceptVerbs( HttpVerbs.Post )]
        public ActionResult Create( FormCollection collection )
        {
            try
            {             
                MembershipCreateStatus status = MembershipCreateStatus.UserRejected;
                MembershipUser user = null;   
                if( collection[ "Password" ].Equals( collection[ "Confirmpw" ], StringComparison.CurrentCultureIgnoreCase ) )
                {
                    user = Membership.CreateUser( collection[ "Username" ], collection[ "Password" ], collection[ "Email" ], null, null, true, out status );
                }
                if( status == MembershipCreateStatus.Success )
                    return RedirectToAction( "Index" );
                else
                    return RedirectToAction( "Error" );
            }
            catch
            {
                return View( "Error" );
            }
        }

編寫virtual method for member


 #region virtual method for member

        public virtual RedirectToRouteResult UnlockUser( Guid key )
        {
            var user = Membership.GetUser(key);           
            user.UnlockUser();//解除鎖定
            return RedirectToUserPage( user );
        }

        public virtual ActionResult DeleteUser(Guid key)
        {
            var user = Membership.GetUser(key);          
            Membership.DeleteUser(user.UserName, true);//刪除成員
            return RedirectToAction("Index");
        }

        #endregion

Add Create View

image 

新增test123成員

image image

刪除test123成員

image image

 Edit In Controller


// GET: /System/Edit/5

        public ActionResult Edit(Guid key)
        {
            var user = Membership.GetUser(key);            
            ViewData["AllRoles"] = Roles.GetAllRoles().OrderBy(x => x).ToList();
            ViewData["UsersRoles"] = Roles.GetRolesForUser(user.UserName).OrderBy(x => x).ToList();
            return View(systemrepository.Editusers(key));//指向systemrepository
        }

        //
        // POST: /System/Edit/5

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Edit( Guid key, FormCollection collection )
        {
            try
            {   
                var user = Membership.GetUser(key);
                //設定白名單
                UpdateModel( user, new[] { "Email", "Comment", "Isapproved" }, 
                    collection.ToValueProvider() );              
                Membership.UpdateUser(user);//更新
                return RedirectToUserPage( user );
            }
            catch
            {
                return RedirectToAction( "Error" );
            }
        }

 

 

編寫virtual method for password 


 #region virtual method for password
     
        public virtual ViewResult ResetPassword()
        {           
            String userName = Request.Form["UserName"];          
            var user = Membership.GetUser(userName);
            var pwd = user.ResetPassword(null);
            ViewData["newpw"] = pwd;
            return View();
        }

        #endregion

 Add Edit View

image

只列出須自行編寫的表現層code

由於controller傳給view含有list類型,所以實做IList泛型集合,並循環顯示出相關資料。


<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <%	       
        var allRoles = (IList)ViewData["AllRoles"];
	    var usersRoles = (IList)ViewData["UsersRoles"];        
    %>
     .....
    ......
    <% using( Html.BeginForm( "ResetPassword", "System" ) )
   { %>
   <fieldset>
     <legend>密碼修改</legend>     
      <% foreach( var item in Model )
         { %>  
     <% =Html.Hidden( "Username", Html.Encode( item.Username ) )%>
    <div>
	<label>最近密碼變更時間:</label>
	<div><% =item.Createdate != item.Lastpasswordchangeddate ? item.Lastpasswordchangeddate : "從未變更密碼"%></div>
	</div>  

	<div><input type="submit" value="重設" /></div>
   </fieldset>
      <%} %>
  <%} %>   
    
  <fieldset>
	<legend>角色修改</legend>    
	<% if( ( ( IList ) ViewData[ "AllRoles" ] ).Count > 0 )
    { %>
	  <% foreach( String role in allRoles )
      { %>
        <% foreach( var item in Model )
         { %>  
	    <div>
		  <% if( usersRoles.Contains( role ) )
            { %>
		     [<% =Html.ActionLink( "移除", "RemoveuserFromrole", "System", new
              {
                key = Html.Encode(item.key ),
                roleName = Html.Encode( role )}, null )%>]<% }
            else
            { %>
		     [<% =Html.ActionLink( "加入", "AdduserTorole", "System", new
               {
                key = Html.Encode(item.key ),
                roleName = Html.Encode( role )}, null )%>]
		 <% } %>
		   <% =Html.ActionLink( role, "Role", "System", new
            {
              id = Html.Encode( role )}, null )%>
          <%} %>
	   </div>
	<% } %>
  <% }
  else
    { %>
	<div>還未加入任何角色</div>
	<% } %>	
  </fieldset>  
  
   <div>
        <%=Html.ActionLink("Back to List", "Index") %>
    </div>  

</asp:Content> 

 編輯test123

image image 

重設test123密碼(實際應用上勿使用預設加密演算法)

Add ResetPassword View


  <h2>ResetPassword</h2>
    <fieldset>
    <legend>重新產生密碼</legend>
    <p>新密碼:<b><% =Html.Encode(ViewData["newpw"])%></b></p>	
    </fieldset>

image image image

將test123加入 Normal角色中

image image

這樣就完成了成員和角色管理功能了。

 

賀!一百篇達成

自己從去年8月加入點部落格後,藉由寫部落格文章提升自己,也認識了很多同好

收穫說真的還不少,期望自己在往後的日子能繼續持續下去,最後,先預祝大家虎年行大運。