I am using auth0 to maintain users details. and I am following This article.
I downloaded project which is using default lock screen, and it's working fine, I am able to create user and login, logout.
When I try with custom login view, and when I try to login with my credentials, It's giving me error "The connection is not found".
I am not sure, Which connection I need to pass here.
Below is the code which I paste from mentioned article.
[HttpPost]
public async Task<ActionResult> Login(LoginViewModel vm, string returnUrl = null)
{
if (ModelState.IsValid)
{
try
{
AuthenticationApiClient client =
new AuthenticationApiClient(
new Uri($"https://{ConfigurationManager.AppSettings["auth0:Domain"]}/"));
var result = await client.AuthenticateAsync(new AuthenticationRequest
{
ClientId = ConfigurationManager.AppSettings["auth0:ClientId"],
Scope = "openid",
Connection = "Database-Connection", // Specify the correct name of your DB connection
Username = vm.EmailAddress,
Password = vm.Password
});
// Get user info from token
var user = await client.GetTokenInfoAsync(result.IdToken);
// Create claims principal
var claimsIdentity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.NameIdentifier, user.UserId),
new Claim(ClaimTypes.Name, user.FullName ?? user.Email),
new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "ASP.NET Identity", "http://www.w3.org/2001/XMLSchema#string")
}, DefaultAuthenticationTypes.ApplicationCookie);
// Sign user into cookie middleware
AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = false }, claimsIdentity);
return RedirectToLocal(returnUrl);
}
catch (Exception e)
{
ModelState.AddModelError("", e.Message);
}
}
return View(vm);
}
Below is Error I am getting,
I am passing correct connection name in AuthenticationRequest also as below image,
You need to make sure that the Connection name specified in the AuthenticationRequest instance that you pass into AuthenticateAsync maps to an existing database connection within your Auth0 account.
More specifically, you're currently passing "Database-Connection"as the name of the connection and you need to ensure that either a connection with that name exists or change your code:
new AuthenticationRequest {
// ...
Connection = "Database-Connection",
Username = vm.EmailAddress,
Password = vm.Password
}
Related
I have just started to use Asp.Net Core and I managed to create a mvc project. In This project I have created an API and it is secured with token based authorization.I have also used identity framework for user auhentication. Now I want to consume this API to perform CRUD operations with passing token but have no clear idea how to do that. After searching similar questions what I have tried is generate the token using user credentials (username, password) when user successfully logged in or registered and attach the generated token to header and as far as I know it will be passed through each subsequent request.
First I tried creating a method to call to generate the token after success login or registration. This includes in same controller which used for login and registration.
Token generate method
public string GenerateAuthToken(ApplicationUser applicationUser)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_configuration.GetSection("JWT")["TokenSignInKey"]);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[] {
new Claim(type:JwtRegisteredClaimNames.Sub, applicationUser.Id),
new Claim(type:JwtRegisteredClaimNames.Email, applicationUser.Email),
new Claim(type:JwtRegisteredClaimNames.Iat,
value:DateTime.Now.ToUniversalTime().ToString())
}),
Expires = DateTime.UtcNow.AddHours(1),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),
SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var stringToken = tokenHandler.WriteToken(token);
return stringToken;
}
I call this after success user login and register,
public async Task<IActionResult> Register(RegisterViewModel registerViewModel)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = registerViewModel.Username,
Email = registerViewModel.Email};
var result = await _userManager.CreateAsync(user, registerViewModel.Password);
if (result.Succeeded)
{
await _signInManager.SignInAsync(user, isPersistent: false);
var token = GenerateAuthToken(user);
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new
AuthenticationHeaderValue("bearer", token);
return RedirectToAction("Index", "Home");
}
ModelState.AddModelError("", "User Registration Failed");
}
return View(registerViewModel);
}
When this executed, the token is successfully generated but does not attach the token. I do not know if I am doing any wrong here. But I found someone facing the same issue but has tried different way to achieve this. I think it is the correct way but not sure. Instead of generate the token on success login, have to generate it each api call. According to this solution I created another controller and action to generate the token.
public async Task<IActionResult> GetToken([FromBody] AuthViewModel authViewModel)
{
var user = _context.Users.FirstOrDefault(u => u.Email == authViewModel.Email);
if (user != null)
{
var signInResult = await _signInManager.CheckPasswordSignInAsync(user,
authViewModel.Password, false);
if (signInResult.Succeeded)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_configuration.GetSection("JWT")
["TokenSignInKey"]);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[] {
new Claim(type:JwtRegisteredClaimNames.Sub,authViewModel.Email),
new Claim(type:JwtRegisteredClaimNames.Email,
authViewModel.Email),
new Claim(type:JwtRegisteredClaimNames.Iat,
value:DateTime.Now.ToUniversalTime().ToString())
}),
Expires = DateTime.UtcNow.AddHours(1),
SigningCredentials = new SigningCredentials(new
SymmetricSecurityKey(key),
SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var stringToken = tokenHandler.WriteToken(token);
return Ok(new { Token = stringToken });
}
return BadRequest("Invalid User");
}}
AuthViewModel
public class AuthViewModel
{
[Required]
public string Email { get; set; }
[Required]
public string Password { get; set; }
}
I added authViewModel to accept logged user credentials since I don't want add them manually, Then I have created another controller to perform the CRUD same as the above mentioned link Please note that I followed the solution mentioned below that page.
private async Task<string> CreateToken()
{
var user = await _userManager.GetUserAsync(User);
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost:7015/Auth");
request.Content = JsonContent.Create(new AuthViewModel{
Email = user.Email, Password = user.PasswordHash
});
var client = _clientFactory.CreateClient();
HttpResponseMessage response = await client.SendAsync(request);
var token = await response.Content.ReadAsStringAsync();
HttpContext.Session.SetString("JwToken", token);
return token;
}
request.Content I added to match my solution since token should be generated using user credentials. But I have no idea how to pass the logged in user's credentials with the request. This does not work. It is not possible to access the user password.
This is how I called the token generate action to perform CRUD. And I use JQuery Ajax to call the GetAllSales endpoint.
public async Task<IActionResult> GetAllSales()
{
string token = null;
var strToken = HttpContext.Session.GetString("JwToken");
if (string.IsNullOrWhiteSpace(strToken))
{
token = await CreateToken();
}
else
{
token = strToken;
}
List<Sale> sales = new List<Sale>();
var client = _clientFactory.CreateClient();
var request = new HttpRequestMessage(HttpMethod.Get,
"http://localhost:7015/api/Sales");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
HttpResponseMessage response = await client.SendAsync(request,
HttpCompletionOption.ResponseHeadersRead);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
var apiString = await response.Content.ReadAsStringAsync();
sales = JsonConvert.DeserializeObject<List<Sale>>(apiString);
}
Ok(sales);
}
This does not work. An exception throws
'System.InvalidOperationException: Unable to resolve service for type 'System.Net.Http.IHttpClientFactory' while attempting to activate '_7_ElevenRetail.Controllers.AccessApiController'.
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)'
Please suggest me and show me how to achieve this correctly. I am expecting all of your help. Thank you.
System.InvalidOperationException: Unable to resolve service for type 'System.Net.Http.IHttpClientFactory' while attempting to activate '_7_ElevenRetail.Controllers.AccessApiController'
This issue means you inject IHttpClientFactory in AccessApiController without registering the service in Program.cs.
Register IHttpClientFactory by calling AddHttpClient in Program.cs:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddHttpClient();
I'm using following code to call Microsoft Graph API:
private static void GraphAPICallTest()
{
try
{
string authority = "https://login.microsoftonline.com/common/oauth2/token";
string resrouce = "https://graph.microsoft.com";
string clientId = "{clientid}";
string userName = "userid#test.com";
string password = "{userpassword}";
UserPasswordCredential userPasswordCredential = new UserPasswordCredential(userName, password);
AuthenticationContext authContext = new AuthenticationContext(authority);
var result = authContext.AcquireTokenAsync(resrouce, clientId, userPasswordCredential).Result;
var graphserviceClient = new GraphServiceClient(
new DelegateAuthenticationProvider(
(requestMessage) =>
{
var access_token = authContext.AcquireTokenSilentAsync(resrouce, clientId).Result.AccessToken;
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", access_token);
return Task.FromResult(0);
}));
var a = graphserviceClient.Me.Request().GetAsync().Result;
Console.WriteLine("Success");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex}");
}
Console.ReadLine();
}
When I use any user from Azure AD this code works just fine. but if i use personnel account it errors out with following error.
ADSTS65001: The user or administrator has not consented to use the application with ID 'c15fd791-7a49-424b-a938-2a9464476277' named 'OneDriveWebAppTest'. Send an interactive authorization request for this user and resource.
Trace ID: 5f31be27-dfdd-410b-af41-e769b2573d00
Correlation ID: 9c8c9f60-c56d-4845-a223-37f5232c6210
Timestamp: 2017-12-11 13:58:39Z
Yes, error is asking about consenting with that personnel user. But even after doing the consent with that user, the error still persist.
Not sure if i'm missing anything.
I'm trying to upload an video to my YouTube account with the following code in my ActionResult in my asp.net MVC project:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload([Bind(Include = " Title, Description")] HttpPostedFileBase uploadFile, Videos videos)
{
var credential = AuthYouTube();
YouTubeService youtubeService = new YouTubeService(new
YouTubeService.Initializer()
{
ApplicationName = "app-name",
HttpClientInitializer = credential
});
// Do Stuff with the video here.
}}
The AuthYouTube() looks like this (the same controller):
public UserCredential AuthYouTube()
{
string filePath = Server.MapPath("~/Content/YT/client_secret.json");
UserCredential credential;
try{
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
// This OAuth 2.0 access scope allows for full read/write access to the
// authenticated user's account.
new[] { YouTubeService.Scope.Youtube },
"username#domain.com",
CancellationToken.None,
new FileDataStore(Server.MapPath("~/Content/YT"),true)
).Result;
};
return credential;
}
catch(EvaluateException ex)
{
Console.WriteLine(ex.InnerException);
return null;
}
}
I have stored my client_secret.json that I downloaded from Google Developer Console inside the [project]/Content/YT. (Also tried inside the /App_Data folder.
When uploading the debugger is showing the folowwing message:
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ComponentModel.Win32Exception: Access is denied
Place where the error occures:
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
StackStrace:
[Win32Exception (0x80004005): Access is denied]
Microsoft.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +115
Microsoft.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccess(Task task) +78
Google.Apis.Auth.OAuth2.<AuthorizeAsync>d__1.MoveNext() in C:\Users\mdril\Documents\GitHub\google-api-dotnet-client\Src\GoogleApis.Auth.DotNet4\OAuth2\GoogleWebAuthorizationBroker.cs:59
[AggregateException: One or more errors occurred.]
System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification) +4472256
Project.Controllers.VideosController.AuthYouTube() in d:\dev\Development\project\project\Controllers\VideosController.cs:133
project.Controllers.VideosController.Upload(HttpPostedFileBase uploadFile, Videos videos) in d:\dev\project\project\Controllers\VideosController.cs:71
What is the reason of this?
- Google API?
- folder / IIS rights?
Update 01-02-2016
Could it be some access error on the API side?
If not, could somebody please provide me the steps to grand the right IIS rights, still get the error after giving folder permissions.
Running the following code DOES create the folder as intended inside my App_Data, but also returns the same 'Access denied' error. The folder is empty.
var path = HttpContext.Current.Server.MapPath("~/App_Data/Drive.Api.Auth.Store");
// here is where we Request the user to give us access, or use the Refresh Token that was previously stored in %AppData%
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets { ClientId = clientId, ClientSecret = clientSecret }
, scopes
, userName
, CancellationToken.None
, new FileDataStore(path,true)).Result;
Could somebody please explain how to get this working?
After ready the documentation again I found a way to get access to the API and upload my videos to YouTube. I hope I can clarify the way i did this.
How i did this:
https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth#web-applications-aspnet-mvc
Create an callback controller:
using Google.Apis.Sample.MVC4;
namespace Google.Apis.Sample.MVC4.Controllers
{
public class AuthCallbackController : Google.Apis.Auth.OAuth2.Mvc.Controllers.AuthCallbackController
{
protected override Google.Apis.Auth.OAuth2.Mvc.FlowMetadata FlowData
{
get { return new AppFlowMetadata(); }
}
}
}
Create class and fill-in the credentials:
using System;
using System.Web.Mvc;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Mvc;
using Google.Apis.YouTube.v3;
using Google.Apis.Util.Store;
namespace Google.Apis.Sample.MVC4
{
public class AppFlowMetadata : FlowMetadata
{
private static readonly IAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = "PUT_CLIENT_ID_HERE",
ClientSecret = "PUT_CLIENT_SECRET_HERE"
},
Scopes = new[] { YouTubeService.Scope.YoutubeUpload },
DataStore = new FileDataStore(HttpContext.Current.Server.MapPath("~/App_Data/clientsecret.json")),
});
public override string AuthCallback
{
get { return #"/AuthCallback/Upload"; }
}
public override string GetUserId(Controller controller)
{
// In this sample we use the session to store the user identifiers.
// That's not the best practice, because you should have a logic to identify
// a user. You might want to use "OpenID Connect".
// You can read more about the protocol in the following link:
// https://developers.google.com/accounts/docs/OAuth2Login.
var user = controller.Session["user"];
if (user == null)
{
user = Guid.NewGuid();
controller.Session["user"] = user;
}
return user.ToString();
}
public override IAuthorizationCodeFlow Flow
{
get { return flow; }
}
}
}
In my ActionResult I set the YoutubeService. the creating of my video take place inside my Upload POST
Your own controller (mine is for the /upload action):
public async Task<ActionResult> Upload(CancellationToken cancellationToken)
{
var result = await new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).AuthorizeAsync(cancellationToken);
if (result.Credential != null)
{
var youtubeService = new YouTubeService(new BaseClientService.Initializer
{
HttpClientInitializer = result.Credential,
ApplicationName = "name",
});
return View();
}
else
{
return new RedirectResult(result.RedirectUri);
}
}
For uploading logic see: https://developers.google.com/youtube/v3/code_samples/dotnet#upload_a_video
Set redirect URL in Google Developers console
In the Google Developers Console set the Authorized redirect URIs value to something like (my controller is called videos): http://www.domainname.com/Videos/Upload
**Using a single oAuth account **
Insted of saving the client id (GUID, see GetUserId inside AppFlowMetadata file) inside my session I now use one single id so I could use the same token/responsive for all the users.
Situation:
I have a Web API 2 project which acts as an Authorization server (/token endpoint) and a resource server. I am using the template that comes out of box with ASP.Net Web API minus any MVC reference.
The Start.Auth is configured as below:
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// 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.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
var facebookAuthenticationOptions = new FacebookAuthenticationOptions()
{
AppId = ConfigurationManager.AppSettings["Test_Facebook_AppId"],
AppSecret = ConfigurationManager.AppSettings["Test_Facebook_AppSecret"],
//SendAppSecretProof = true,
Provider = new FacebookAuthenticationProvider
{
OnAuthenticated = (context) =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken));
return Task.FromResult(0);
}
}
};
facebookAuthenticationOptions.Scope.Add("email user_about_me user_location");
app.UseFacebookAuthentication(facebookAuthenticationOptions);
}
The MVC 5 Client (different Project) uses the Web API app for authorization and data. Below is the code to retrieve the Bearer token in case of Username/Password store:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
model.ExternalProviders = await GetExternalLogins(returnUrl);
return View(model);
}
var client = Client.GetClient();
var response = await client.PostAsync("Token",
new StringContent(string.Format("grant_type=password&username={0}&password={1}", model.Email, model.Password), Encoding.UTF8));
if (response.IsSuccessStatusCode)
{
return RedirectToLocal(returnUrl);
}
return View();
}
Problem
I could retrieve the Bearer token and then add it to the Authorization Header for subsequent calls. I think that would be ok in case of an Angular App or a SPA. But I think there should be something in MVC that handles it for me, like automatically store it in a cookie and send the cookie on subsequent requests. I have searched around quite a lot and there are posts which hint towards this (Registering Web API 2 external logins from multiple API clients with OWIN Identity) but I haven't been able to figure out what to do after I get a token.
Do I need to add something in the MVC app Startup.Auth?
Ideally, I need the functionality which the AccountController in ASP.Net Template (MVC + Web API) gives out of box (Logins, Register, External logins, forget password etc etc...) but with the MVC and Web API in different projects.
Is there a template or a git repo which has this boiler plate code?
Thanks in advance!
Update
Incorporating #FrancisDucharme suggestions, below is the code for GrantResourceOwnerCredentials().
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user.UserName);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
//Add a response cookie...
context.Response.Cookies.Append("Token", context.Options.AccessTokenFormat.Protect(ticket));
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
But I can't still seem to get that Cookie or figure out what to do next.
Restating Questions:
What would be the correct way to authenticate, authorize and call Web API methods (Auth and Resource server) from an MVC client?
Is there boilerplate code or template for AccountController which does the basic plumbing (Login, register - internal/external, forgot password etc.)?
You could have your Startup class return a response cookie that the client will then return on all subsequent requests, here's an example. I would do it in GrantResourceOwnerCredentials.
public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
//your authentication logic here, if it fails, do this...
//context.SetError("invalid_grant", "The user name or password is incorrect.");
//return;
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
AuthenticationTicket ticket = new AuthenticationTicket(identity);
//Add a response cookie...
context.Response.Cookies.Append("Token", context.Options.AccessTokenFormat.Protect(ticket));
context.Validated(ticket);
}
The Startup class:
public partial class Startup
{
public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
public Startup()
{
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
}
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigureOAuth(app);
//I use CORS in my projects....
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
WebApiConfig.Register(config);
}
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true, //I have this here for testing purpose, production should always only accept HTTPS encrypted traffic.
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
Provider = new AuthorizationServerProvider()
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
}
}
That assumes the client has cookies enabled, of course.
Then, modify your MVC headers to add the Authorization header to all requests as such.
In the ActionFilterAttribute, fetch your cookie value (Token) and add the header.
Instead of storing in session, I have added it to the the DefaultRequestHeaders as shown below so I don't need to add this in every call I make to Web API.
public async Task AuthenticateUser(string username, string password)
{
var data = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", username),
new KeyValuePair<string, string>("password", password)
});
using (HttpResponseMessage response = await APIClient.PostAsync("/Token", data))
{
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsAsync<AuthenticatedUser>();
APIClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.Access_Token);
}
else
{
throw new Exception(response.ReasonPhrase);
}
}
}
I hope you're all great, this time I'm here to ask an issue that I can't figure it out and it's about Identity, the thing is I want to get de User Id from the Claims principal or whereever it is, right now the only thing that I have is
var principal = ClaimsPrincipal.Current;
var id1 = principal.Claims.FirstOrDefault(c => c.ValueType == ClaimTypes.NameIdentifier);
but when I try to get the UserId and I go to the information inside the claims I can't find the value even if I saved it in the AuthorizationTicket at login.
I'm working with MVC template and Web api service My service is hosted in IIS and with it I manage the authentication with an accountcontroller via Token
this is my AuthenticationProperties
public static AuthenticationProperties CreateProperties(string userName, string userid)
{
IDictionary<string, string> data = new Dictionary<string, string> { { "userName", userName }, { "userId", userid } };
return new AuthenticationProperties(data);
}
and my GrantResourceOwnerCredentiales
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
//var userManager = DependencyResolver.Current.GetService<ApplicationUserManager>();
AppJobSeeker user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, OAuthDefaults.AuthenticationType);
ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager, CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user.UserName, user.Id);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);...
And I have a method which creates a AuthenticationTicket and it receive the UserName and the UserId as well
private void CreateTicket(SignInResult result, SignInModel model, string returnUrl)
{
//Let's keep the user authenticated in the MVC webapp.
//By using the AccessToken, we can use User.Identity.Name in the MVC controllers to make API calls.
FormsAuthentication.SetAuthCookie(result.AccessToken, model.RememberMe);
//Create an AuthenticationTicket to generate a cookie used to authenticate against Web API.
//But before we can do that, we need a ClaimsIdentity that can be authenticated in Web API.
var claims = new[]
{
new Claim(ClaimTypes.Name, result.UserName), //Name is the default name claim type, and UserName is the one known also in Web API.
new Claim(ClaimTypes.NameIdentifier, result.UserId), //If you want to use User.Identity.GetUserId in Web API, you need a NameIdentifier claim.
};
//Generate a new ClaimsIdentity, using the DefaultAuthenticationTypes.ApplicationCookie authenticationType.
//This also matches what we've set up in Web API.
var authTicket = new AuthenticationTicket(new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie), new AuthenticationProperties
{
ExpiresUtc = result.Expires,
IsPersistent = model.RememberMe,
IssuedUtc = result.Issued,
RedirectUri = returnUrl
});
...
Everithing looks fine when I do the login but when a I go to another controller I can't retreive the UserId
Have you added the [Authorize] attribute to your controller?
[Authorize]
public class AuthorizeController : ApiController
{
public Task<IHttpActionResult> GetUserId()
{
return Ok(HttpContext.Current.User.Identity.GetUserId());
}
}