Showing posts with label Localization. Show all posts
Showing posts with label Localization. Show all posts

Friday, January 15, 2016

Applying c# Extensions for Claims-based Authentication

In My AccountController, I have NewLogin Action:
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult NewLogin(LocalAccountLoginViewModel model, string returnUrl)
        {
            using (UserService _service = new UserService())
            {
                CFG_Users user = _service.GetUserById(model.UserId);
                if (user == null)
                {
                    DisplayErrorPage("Error", Resources.Account.LoginResources.UserNotExist);
                    return View(model);
                }
                if (!user.Enabled)
                {
                    DisplayErrorPage("Error", Resources.Account.LoginResources.UserNotActive);
                    return View(model);
                }

                if (!_service.ValidateUser(model.UserId, model.Password))
                {
                    DisplayErrorPage("Error", Resources.Account.LoginResources.InvalidUserNamePassword);
                    return View(model);
                }

                var claims = new List<Claim>();

                // create *required* claims
                claims.Add(new Claim(ClaimTypes.NameIdentifier, user.IDUser));
                claims.Add(new Claim(ClaimTypes.Name, _service.GetUserName(user)));
                claims.Add(new Claim("IsAdmin", _service.IsUserAdmin(user).ToString()));
                claims.Add(new Claim("Culture", user.IDLanguage.Trim()));

                IdentitySignin(claims, model.UserId, model.RememberMe);

                if (!string.IsNullOrEmpty(returnUrl))
                    return Redirect(returnUrl);

                return RedirectToAction("Index", "Dashboard", null);
            }
        }
The NewLogin action  applied following helper method to finish the sign in process.
        /// <summary>
        /// Helper method that adds the Identity cookie to the request output
        /// headers. 
        /// </summary>
        /// <param name="claims"></param>
        /// <param name="providerKey"></param>
        /// <param name="isPersistent"></param>
        public void IdentitySignin(List<Claim> claims, string providerKey = null, bool isPersistent = false)
        {
            var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);

            // add to user here!
            AuthenticationManager.SignIn(new AuthenticationProperties()
            {
                AllowRefresh = true,
                IsPersistent = isPersistent,
                ExpiresUtc = DateTime.UtcNow.AddDays(1)
            }, identity);

            var userCulture = identity.GetCulture();
            // set lang to the user's language 
            if (RouteData.Values["lang"] != userCulture)
            {
                RouteData.Values["lang"] = userCulture;
                SetThreadCulture(userCulture);
            }
        }

        public void IdentitySignout()
        {
            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie,
                DefaultAuthenticationTypes.ExternalCookie);
        }

        private IAuthenticationManager AuthenticationManager
        {
            get { return HttpContext.GetOwinContext().Authentication; }
        }
Note I applied C# Extensions so I can easily use GetCulture for my identity. Here is the Claim Identity Extension code:
using System.Collections.Generic;
using System.Security.Claims;
using System.Linq;
namespace MyApp.Extensions
{
    public static class ClaimsIdentityExtensions
    {
        public static bool IsAdmin(this ClaimsIdentity identity)
        {
            var claims = identity.Claims;
            return bool.Parse(GetClaim(claims, "IsAdmin")); 
        }

        public static string GetCulture(this ClaimsIdentity identity)
        {
            var claims = identity.Claims;
            return GetClaim(claims, "Culture"); //todo: replace Culture with a Const
        }

        public static string GetName(this ClaimsIdentity identity)
        {
            var claims = identity.Claims;
            return GetClaim(claims, ClaimTypes.Name); ;
        }

        public static string GetUserId(this ClaimsIdentity identity)
        {
            var claims = identity.Claims;
            return GetClaim(claims, ClaimTypes.NameIdentifier);
        }

        private static string GetClaim(IEnumerable<Claim> claims, string key)
        {
            var claim = claims.ToList().FirstOrDefault(c => c.Type == key);
            if (claim == null)
                return null;
            return claim.Value;
        }
    }
}

Reference:
http://leastprivilege.com/2012/10/08/custom-claims-principals-in-net-4-5/

Friday, January 8, 2016

How to share Localization Resource in ASP.Net 5 MVC with Javascript

ASP.Net MVC projects can use Resource files to do localization. Its very easy to use those resource files in razor view files. For each resource, there are multiple resource files referring to different languages. ASP.Net treats those resource files as one resource class. The application will use specific language resource during the run time while one language is selected.

Regarding the Javascript, if we want to apply those resource files, we need to send them to Javascript one by one in razor file. To avoid those tedious process and to improve the independence of Javascript, we can create resource section in razor file using HTML 5 section tag. And let Javascript to read those resource by themselves. Here is the code in view:
<section class="myResouceLabels"
    data-Message1 = "@MyResources.MyMessage1"
    data-Message2 = "@MyResources.MyMessage2">
</section>
In your Javascript:
    // Return a message contained in the container
    function GetResourceMessage(msgId) {
        var container = $(".myResouceLabels");
        if (container.length == 0) return;
        return container.attr(msgId);
    }
    ....
    alert(GetResourceMessage(data-Message1);
    alert(GetResourceMessage(data-Message1);
Note section tag contained all attributes with data as leading string, which is different than other tags. Be careful not to make mistake!!!

Definitely, you need css decorating to let the section don't be displayed.
myResouceLabels { display: none }