Access claims in web api controller in mvc5 project - asp.net-web-api

I have a MVC5 project with ASP.NET Identity. I'm using Claims in my MVC5 controllers like below.
public ActionResult Index()
{
var prinicpal = (ClaimsPrincipal)Thread.CurrentPrincipal;
var email = prinicpal.Claims.Where(c => c.Type == ClaimTypes.Email).Select(c => c.Value).SingleOrDefault();
}
However the Claims are not available in a WebApi controller in the same project. What do I have to do to get access to the Claims of the logged in user in a WebApi Controller in a MVC5 project?
Thank You.

Make sure your WebAPI controller or action is decorated with [Authorize]. You will never get current user context for anonymous requests.
[HttpGet]
[Authorize]
public IHttpActionResult Get()
{
try
{
var user = this.User as ClaimsPrincipal; //OR
var prinicpal = (ClaimsPrincipal)Thread.CurrentPrincipal;
var email = prinicpal.Claims.Where(c => c.Type == ClaimTypes.Email).Select(c => c.Value).SingleOrDefault();
}
catch (Exception ex)
{
return InternalServerError(ex);
}
return Ok();
}

Related

ASP.NET Core 3.1 MVC redirect in a custom AuthorizationHandler

In a ASP.NET Core 2 MVC app, I had a custom AuthorizationHandler that redirected blocked users back to the home page.
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IsAllowedIpAddressRequirement requirement)
{
// Cast the context resource
if (context.Resource is AuthorizationFilterContext cxt)
{
// Failed!
cxt.Result = new RedirectToActionResult("Index", "Home", new { msg = "Your auth has failed." });
context.Succeed(requirement);
}
...
}
Since migrating to ASP.NET Core 3.1, the context is an object of class Microsoft.AspNetCore.Routing.RouteEndpoint, which has no Result property.
How can I redirect the user to a specific page?
I had the same problem and to solve it I changed to Filter (IAsyncResourceFilter) instead of Policy.
You can wrap your authorization logic into a policy and then invoke the IAuthorizationService and redirect anywhere/anytime you need.
Example:
public class MySampleActionFilter: IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
//if failed
context.Result = new RedirectToRouteResult(new RouteValueDictonary(new
{
controller = "Your Controller",
action = "Your Action"
}));
}
}
By the way, this is for .net Core 3 and above
Documentation
if you want to user redirect to some page like login page, if user didn't has access, you could following below steps for fix it:
into HandleRequirementAsync method
if (Condition())
{
context.Succeed(requirement);
}
else {
context.Fail();
}
if user did has access, execute context.Succeed(requirement); and if user didn't has access, execute context.Fail();
into startup.cs => ConfigureServices method
services.ConfigureApplicationCookie(options =>
{
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromHours(12);
options.LoginPath = "/Account/Login";
options.AccessDeniedPath = "/Account/AccessDenied";
options.SlidingExpiration = true;
});
in line that we write
options.LoginPath = "/Account/Login";
we appointment users after failing in HandleRequirementAsync method for checking access, being redirected to controller 'home' controller and 'login' actiion.
i'll hope my answer be useful for friends.

How to redirect from Identity Area to Admin in ASP.NET CORE 2

I cant redirect from Identity Area:
if (role=="Admin")
{
return RedirectToAction("Index","Home",new { Area=Input.Role ,id=9});
}
To Admin Area Controller-Home,Action-Index.Always redirect me to Index in the Identity Area;
looking at your code I am still scratching my head as to the reason that someone would specify the Role at login. Can you articulate the reasoning behind this?
Simplest answer is inline with the code within the OnPostAsync(); that resides in
//this because of the routes you have in StartUp.cs
[Authorize(Roles ="Admin")]
[Area("admin")]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}
Login.cs Page...
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(Input.Username, Input.Password, Input.RememberMe, lockoutOnFailure: true);
if (result.Succeeded)
{
var user = await userManager.GetUserAsync(User); // Claims Principle
if (await userManager.IsInRoleAsync(user, "Admin"))
{
//SIMPLEST ANSWER since you using mixed environment with PAGES
return LocalRedirect("~/admin");
}
//TODO:
_logger.LogInformation("User logged in.");
return LocalRedirect(returnUrl);
}
Check your issues below one by one:
I got error A method 'CakeStore.App.Areas.Admin.Controllers.HomeController.Index (CakeStore.App)' must not define attribute routed actions and non attribute routed actions at the same time, you should not define [HttpGet(Name ="AdminPanel")] and [Route(nameof(Admin) + "/[controller]")] at the same time.
//[HttpGet(Name ="AdminPanel")]
[Area(nameof(Admin))]
[Route(nameof(Admin) + "/[controller]")]
public IActionResult Index()
{
return View();
}
For var role = this.roleManage.GetUrl(Input.Username);, it will retrive the role by username, check whether you got expected role Admin.
return RedirectToAction("Index","Home",new { Area=Input.Role ,id=9});, you did not define id in Index, there is no need to add id route.

asp.net core 2.1 tempdata empty with redirecttoaction

I have an asp.net core 2.1 project and I try to use TempData with RedirectToAction but it's always null (without Error)
Here is my ConfigureServices method
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
//services pour l'authentification
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
{
options.LoginPath = "/Login";
});
//services pour session
services.AddSession(options => {
options.IdleTimeout = TimeSpan.FromMinutes(20);
});
//configuer port https
services.AddHttpsRedirection(options => options.HttpsPort = 443);
Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true;
ManageDI(services);
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddSessionStateTempDataProvider();
}
I have "app.UseSession();" in my Configure method
and here is my code
[HttpGet]
public async Task< IActionResult> ResetPassword(string query)
{
TempData["test"]= "test";
return RedirectToAction(nameof(Login));
}
[HttpGet]
public IActionResult Login(string returnUrl = null)
{
var b = TempData["test"];
//b is always null when calling ResetPassword action
var model = new Models.Account.LoginModel{
ReturnUrl = returnUrl
};
return View(model);
}
What did I forget please ?
Thanks
It's not entirely clear what the issue is based on the code you've provided, but since you mention that it's null in your ResetPassword action from within your Login action, I'm assuming you're not properly persisting the value.
TempData is just that: temporary data. Once it's been accessed, it is removed. Therefore, when you set b here with its value, that's it - it's gone. If you then try to access it in another action later or even just in the view this action returns, it will be null now.
If you need to get the value, but also keep it around for later, you need to use TempData.Peek:
var b = TempData.Peek("test");

Using Action link with Web Api Controller

How can I use ActionLink when calling an action on a controller that is a WebApi controller.
public class RequestController : ApiController
{
[ActionName("CreateAction")]
[ResponseType(typeof(Request))]
public async Task<IHttpActionResult> PostRequest(Request request)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Requests.Add(request);
await db.SaveChangesAsync();
return CreatedAtRoute("DefaultApi", new { id = request.Id }, request);
}
}
in my layout page can I do this
#Html.ActionLink("Request", "CreateAction", "api/Request", new { area = "" }, null)
Jawahar
You can generate a link to an API controller using the standard Url helper property. The following link will point to an Albums controller and pass along an id parameter with a value of 3:
#Url.RouteUrl("DefaultApi", new { httproute=true, controller="Albums", id=3})
Please refer to this link
http://odetocode.com/blogs/scott/archive/2013/03/27/webapi-tip-5-generating-links.aspx

WebSecurity vs FormsAuthentication in ASP.NET MVC4

I guess I am trying to mix two providers in project but I am looking to use websecurity in conjunction to my forms authentication. I need websecurity for OAUTH authentication using Facebook, and google.
The error that I am getting when I try to login using facebook is
To call this method, the Membership.Provider property must be an instance of ExtendedMembershipProvider.
Here are the code samples. How can I use both?
public ActionResult ExternalLoginCallback(string returnUrl)
{
AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
if (!result.IsSuccessful)
{
return RedirectToAction("ExternalLoginFailure");
}
if (OAuthWebSecurity.Login(result.Provider, result.ProviderUserId, createPersistentCookie: false))
{
return RedirectToLocal(returnUrl);
}
if (User.Identity.IsAuthenticated)
{
// If the current user is logged in add the new account
OAuthWebSecurity.CreateOrUpdateAccount(result.Provider, result.ProviderUserId, User.Identity.Name);
return RedirectToLocal(returnUrl);
}
else
{
// User is new, ask for their desired membership name
string loginData = OAuthWebSecurity.SerializeProviderUserId(result.Provider, result.ProviderUserId);
ViewBag.ProviderDisplayName = OAuthWebSecurity.GetOAuthClientData(result.Provider).DisplayName;
ViewBag.ReturnUrl = returnUrl;
return View("ExternalLoginConfirmation", new RegisterExternalLoginModel { UserName = result.UserName, ExternalLoginData = loginData });
}
}
and
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
Could possibly be related to the same issue as me MVC4 ExtendedMembershipProvider and entityframework
.. I removed the universal providers nuget package and this particular error dissappeared.
Also this "very recent" article by Jon Galloway may help.
If you are using Visual Studio, you might want to save yourself all this effort. The MVC 4 Internet template comes with four external identity providers out of the box. I have tested them and Google Accounts, Microsoft account, Facebook login, and Twitter login all work fine, with zero lines of code!
I think the same is provided with the Web Form template too.
More info at http://blogs.msdn.com/b/webdev/archive/2012/08/15/oauth-openid-support-for-webforms-mvc-and-webpages.aspx.
You can use an implementation of ExtendedMembershipProvider. For ex: the built-in SimpleMembershipProvider.
Every ExtendedMembershipProvider IS A MembershipProvider .
Read more at Jon Galloway's Blog.

Resources