2014年11月5日 星期三

自定AuthenticationFilter實現Basic認證

HTTP基本認證
當沒有訪問需要認證(還沒有認證通過)的網站時,瀏覽器自動跳出登入對話框



自定一個 Filter:
public class MyAutheticationAttribute : FilterAttributeIAuthenticationFilter
    {
        /* basic 驗證的 http header
         *     401 Unauthorizted
         *         WWW-Authenticate: Basic realm="Secure Area"
         *     請求登入
         *         Authorization: Basic {base64編碼過的登錄信息}
         */
        public const string AuthoriztionHeaderName = "Authorization";
        public const string WwwAuthenticationHeaderName = "WWW-Authenticate";
        public const string BasicAuthenticationScheme = "Basic";
        private static Dictionary<stringstring> userAccounters;
 
        static MyAutheticationAttribute()
        {
            // 為了簡單測試起見,將一些帳號密碼存放到一個靜態欄位中
            userAccounters = new Dictionary<stringstring>(StringComparer.OrdinalIgnoreCase);
            userAccounters.Add("Ian""1234");
            userAccounters.Add("Peter""1111");
            userAccounters.Add("Jay""2222");
        }
 
        // 具體的認證實現
        public void OnAuthentication(AuthenticationContext filterContext)
        {
            IPrincipal user;
            if (this.IsAuthenticated(filterContext, out user))
            {
                filterContext.Principal = user;
            }
            else
            {
                this.ProcessUnauthenticatedRequest(filterContext);
            }
        }
 
        //
        protected virtual AuthenticationHeaderValue GetAuthenticationHeaderValue(AuthenticationContext filterContext)
        {
            // Authorization 內容
            string rawValue = filterContext.RequestContext.HttpContext.Request.Headers[AuthoriztionHeaderName];
            if (string.IsNullOrEmpty(rawValue))
            {
                return null;
            }
            string[] split = rawValue.Split(' ');
            if (split.Length != 2)
            {
                return null;
            }
            return new AuthenticationHeaderValue(split[0], split[1]);
        }
 
        // 判斷是否通過驗證
        protected virtual bool IsAuthenticated(AuthenticationContext filterContext, out IPrincipal user)
        {
            user = filterContext.Principal;
            if (null != user && user.Identity.IsAuthenticated)
            {
                return true;
            }
            AuthenticationHeaderValue token = this.GetAuthenticationHeaderValue(filterContext);
            if (null != token && token.Scheme == BasicAuthenticationScheme) // "Basic"
            {
                string credential = Encoding.Default.GetString(Convert.FromBase64String(token.Parameter));
                string[] split = credential.Split(':'); // {UserNamr}:{Password}
                if (split.Length == 2)
                {
                    string userName = split[0];
                    string password;
                    if (userAccounters.TryGetValue(userName, out password))
                    {
                        if (password == split[1])
                        {
                            // 認證成功的情況下得到代表請求用戶的 Principal 對象
                            GenericIdentity identiry = new GenericIdentity(userName);
                            user = new GenericPrincipal(identiry, new string[0]);
                            return true;
                        }
                    }
                }
            }
 
            return false;
        }
 
        // 沒有通過請求
        protected virtual void ProcessUnauthenticatedRequest(AuthenticationContext filterContext)
        {
            string parameter = string.Format("realm=\"{0}\"", filterContext.RequestContext.HttpContext.Request.Url.DnsSafeHost);
            AuthenticationHeaderValue challenge = new AuthenticationHeaderValue(BasicAuthenticationScheme, parameter);
            filterContext.HttpContext.Response.Headers[WwwAuthenticationHeaderName] = challenge.ToString();
            filterContext.Result = new HttpUnauthorizedResult();
        }
 
        public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
        {
            // throw new NotImplementedException();
        }
    }

應用在Controller:
    [MyAuthetication]
public class HomeController : Controller
{
    public void Index()
    {
        Response.Write(string.Format("Controller.User: {0}<br/>"this.User.Identity.Name));
        Response.Write(string.Format("HttpContext.User: {0}<br/>"this.ControllerContext.HttpContext.User.Identity.Name));
        Response.Write(string.Format("Thread.CurrentPrincipal.Identity.Name: {0}<br/>"Thread.CurrentPrincipal.Identity.Name));
    }
}



沒有留言: