Showing all posts tagged "Tech"
Claim Based Security In ASP.NET Core In Just 8 Easy Steps
With Microsoft taking the OSI route, ASP.NET Web platform and ASP.NET project have undergone some significant changes. Also ASP.NET MVC Views and Controllers had minor transformation with the new platform skeleton. Let us go through the brief outline of the recent updates and how to implement claim based security in ASP.NET Core.
What is a Claim?
It is an attribute of identity that defines permissions. Permission means the step taken to perform the action and claim reside in the Microsoft.AspNetCore.Identity library. For successful dot net application development, we must look at the basic concepts for building a claim-based security and learn how to implement by creating an application on ASP.NET Core.
First we will create a “Hello World" ASP.NET Core web application using .NET core framework. To learn more about how to use Visual Studio and create ASP.NET Core applications, visit here:
In the above screenshot, the default template of Visual Studio .NET Web Project contains all the namespaces and assemblies required for our test project. Once the project is setup, we now need to focus on implementing a simple functionality -> Add a new Claim during the user registration/creational process and then apply the authorization restriction to the user with the Claim specified.
We need to use the below code in Startup.cs class which will help implement the security at application bootstrap, including security:
public class Startup
{
// Setting up the hosting environment
// and configuration
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true,
reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json",
optional: true);
if (env.IsDevelopment())
{
// For more details on using the user secret store see
// http://go.microsoft.com/fwlink/?LinkID=532709
builder.AddUserSecrets();
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method
// to add services to the container.
public void ConfigureServices(IServiceCollection services) {
// Add framework services.
services.AddDbContext(options =>
options.UseSqlServer(Configuration.GetConnectionString
("DefaultConnection")));
// Add Identity stuff to the application services
services.AddIdentity()
.AddEntityFrameworkStores()
.AddDefaultTokenProviders();
services.AddMvc();
// Add application services.
services.AddTransient();
services.AddTransient();
}
// This method gets called by the runtime. Use this method to
// configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app,
IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection
("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
// Enable the application to use a cookie to store information
// for the signed-in user and to use a cookie to temporarily
// store information about a user logging in with a
// third-party login provider
app.UseIdentity();
// Add external authentication middleware below. To configure
// them, please see http://go.microsoft.com/fwlink/?LinkID=532715
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/
{action=Index}/{id?}");
});
}
}
Next we will look at Models\ApplicationUser.cs class which contains an ApplicationUser class that derives from Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser:
Add profile data for application users by
// adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser
{
}
The above public class will be empty, where we need to add our claims. We will do it by applying code changes to demonstrate Claim-based security in real life using eight easy steps:
Step 1 - Enable Entity Framework Migrations – You need to enable “Entity Framework Migrations" if there are any iterative changes to Claims planned, as ASP.NET Identity uses Code First, auto-migration would be useful to perform database schema updates.
Step 2 - Add Relevant Properties - Now add all relevant properties to the ApplicationUser class (in file Models\ApplicationUser.cs) to store the Claims. We will take "BirthDate" and add this property to ApplicationUser. Do not forget to add the using System clause before class definition.
Step 3 - Add EF Migration – For updating database with the new added field. In the Package Manager Console, perform the following steps:
- Add-Migration "Age"
to create an upgrade script for our modification. - Update-Database
to run a database schema update.
Now, we will implement the filling out of the Birthday value by adding a Birthday parameter to the User Registration form in the Models\AccountViewModels\RegisterViewModel.cs RegisterViewModel class using the below code:
public class RegisterViewModel
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be
at least {2} and at max {1} characters long.",
MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password
and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
[Required]
[Display(Name = "Date of Birth")]
[DataType(DataType.Date)]
public DateTime BirthDate { get; set; }
}
Step 4 - Update the Views\Account\Register.cshtml File – Use the below code and update
...
class="col-md-2 control-label">
class="form-control" />
class="text-danger">
...
We also need to create a new account and test the new added field
Step 5 - Update the Controllers\AccountController.cs Register Method – We need to update the class method to pass the Birthday field in the above screenshot
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task Register(RegisterViewModel model,
string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email,
Email = model.Email, BirthDate = model.BirthDate };
var result = await _userManager.CreateAsync(user,
model.Password);
if (result.Succeeded)
{
// For more information on how to enable account confirmation
// and password reset, please visit
// http://go.microsoft.com/fwlink/?LinkID=532713
// Send an email with this link
// var code = await
// _userManager.GenerateEmailConfirmationTokenAsync(user);
// var callbackUrl = Url.Action("ConfirmEmail",
// "Account", new { userId = user.Id, code = code },
// protocol: HttpContext.Request.Scheme);
// await _emailSender.SendEmailAsync(model.Email,
// "Confirm your account",
// $"Please confirm your account by clicking this link:
// link");
await _signInManager.SignInAsync(user, isPersistent: false);
_logger.LogInformation(3, "User created a new account
with password.");
return RedirectToLocal(returnUrl);
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
Step 6 – Add the Claims - We need to create a mechanism for adding the Claims in ASP.NET Core with Microsoft.AspNetCore.Identity.SignInManager, by default. It includes only username and user identifier claims. SignInManager uses IUserClaimsPrincipalFactory to generate ClaimsPrincipal from TUser (in our case, from ApplicationUser).
We need to create our own implementation of IUserClaimsPrincipalFactory to add custom claims. We do not require the boilerplate code to be generated. We will simply derive it from the default UserClaimsPrincipalFactory which is already implementing IUserClaimsPrincipalFactory.
public class CustomClaimsPrincipalFactory :
UserClaimsPrincipalFactory
IdentityRole>
{
public CustomClaimsPrincipalFactory(
UserManager userManager,
RoleManager roleManager,
IOptions optionsAccessor) :
base(userManager, roleManager, optionsAccessor)
{
}
public async override Task
CreateAsync(ApplicationUser user)
{
var principal = await base.CreateAsync(user);
// Add your claims here
((ClaimsIdentity)principal.Identity).
AddClaims(new[] {
new Claim(ClaimTypes.DateOfBirth,
user.BirthDate.ToString())
});
return principal;
}
}
Step 7 - Register CustomClaimsPrincipalFactory
// This method gets called by the runtime. Use this method
// to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddDbContext(options =>
options.UseSqlServer(Configuration.
GetConnectionString("DefaultConnection")));
// Add Identity stuff to the application services.
services.AddIdentity()
.AddEntityFrameworkStores()
.AddDefaultTokenProviders();
// Add Custom Claims processor
services.AddScoped,
CustomClaimsPrincipalFactory>();
services.AddMvc();
// Add application services.
services.AddTransient();
services.AddTransient();
}
Step 8 – Verify the Claim Security – Once the Claim setup is done with the above code, we now need to verify it. It is a common practice to write custom Authorize filters to verify the availability and particular value of the Claim pair, and then put that filter on the controllers' actions. The Claim “BirthDay" requires more checks, so we will implement verification of the Claim just for demonstration purposes in the Controllers\HomeController.cs About method using the below code:
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
var user = HttpContext.User;
if (!user.HasClaim(c => c.Type ==
System.Security.Claims.ClaimTypes.DateOfBirth))
{
ViewBag.Message = "Cannot detect the Age -
Claim is absent.";
return View();
}
int minAge = 16;
var dateOfBirth = Convert.ToDateTime(user.FindFirst(c =>
c.Type == System.Security.Claims.ClaimTypes.DateOfBirth).Value);
if (calculateAge(dateOfBirth) >= minAge)
{
ViewBag.Message = "Your can view this page.";
}
else
{
ViewBag.Message = "Your cannot view this page -
your age is bellow permitted one.";
}
return View();
}
private int calculateAge(DateTime dateOfBirth)
{
int calculatedAge = DateTime.Today.Year - dateOfBirth.Year;
if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge))
{
calculatedAge--;
}
return calculatedAge;
}
Any Claim can be extracted easily from the HttpContext.User at any point of the project. Now try to verify the code by registering one account with DOB (07/14/2016) and we will see the below result:
In the debug mode we will see the code like this:
Conclusion
This was one way to set up Claim-based security in ASP.NET Core with the help of ASP.NET Core Identity. Previously, it was very easy to add the Claims directly in the ApplicationUser implementation via overriding the GenerateUserIdentityAsync() method. But in ASP.NET Core, we need to implement IUserClaimsPrincipalFactory that is internally used by SignInManager. We also got more structured classes and interfaces implementation in ASP.NET Core, as logically SignInManager should indeed control sign-in processes (including claims) and ApplicationUser should be just an IdentityUser.
Let us know if you faced any difficulty in the comments section.
Posted on February 9th, 2017
Why Use Cloud-Based Order Management System?
Order Management System or OMS is a great solution for retailers, e-commerce businesses to track the orders received from customers in real-time. OMS also tracks the customer information and warehouse inventory on hand, making it easy to manage the entire supply chain. Many enterprises use messy spreadsheets for managing their orders, but that is not the best practice you should follow. Should you buy an OMS product or develop your own OMS and outsource java development services? We will solve the dilemma by first figuring out how OMS fits into your operations.
First let’s answer the below questions:
- Is your business creating orders based on the information received?
- Are you notifying users about the orders being created?
- Is there a warehouse managing your orders?
- Are you generating documents with transaction data after the orders are executed?
- Are you sharing the order documents to the accounting system?
Is your answer "Yes"? then OMS is a perfect fit for your business. Order management includes everything from organizing the orders your receive, stock movements, CRM, returns and refunds, billing and payments and order processing.
How different is order management compared to inventory management?
Not quite. OMS does overlap some aspects of inventory management - like tracking of enough stock for fulfilling the order, or tracking the movement of stock as orders are shipped. Both inventory & order management systems track and take charge of different parts of the supply chain workflow.
Inventory management is focused on the past orders, helping to forecast the future demand, sales trends, and order the right amount of inventory stock, making your inventory efficient. Order management is focused on organizing your real-time orders.
Should the OMS be offline or in the cloud?
The OMS helps with the fulfillment process mentioned above. You can easily track orders from customers, process and organize the fulfillment when a customer purchases something from you until it’s shipped off. It also manages vital information about your customers and sales teams. If your business is growing at rapid pace and requires flexibility and scalability then choosing cloud is a good option. Offline is used by small enterprises working in startup phase and trying to establish their brands in the market. Both cloud and offline are reliable systems to manage your orders. And they are far better than using spreadsheets or another manual system, helping you save time and correcting errors that could definitely be used for something that will grow your business instead of just maintain it!
Cloud Order Management System delivers following benefits:
- Helps in delivering efficient fulfillment process: As all the data is in one place, your fulfillment process will become more efficient with fewer delays. You will start to track better and achieve easy access to your orders and know their statuses.
- Be more organized: You will achieve organized sales orders, making the sales cycle shorter, and minimizing time to process order paperwork. The cloud OMS guarantees fewer errors from manual entry and saves time in sharing order status updates. You also get paid faster with an organized billing data that you can use to quickly make financial decisions.
- Improved tracking: Managing orders in the cloud means you can track orders in real-time, getting updated information and the knowledge of the current state of any of your orders at any time.
Rishabh Software’s mobile order management solution has organizations improve efficiency, reduce errors, and achieve faster supply chain process. Feel free to evaluate the solution. Have you tried any other OMS? Let us know your thoughts in the comments below.
Posted on January 16th, 2017