I want to convert the result into a string and pass it to the navigation path, but I couldn't do it, please help me.
HttpGet Controller
[HttpGet]
[Route("UserId")]
public async Task<ActionResult<ApplicationUser>> GetUserId(string Username)
{
var user = await userManager.FindByNameAsync(Username);
if (user == null)
return StatusCode(StatusCodes.Status500InternalServerError, new Response { Status = "Error", Message = "User not exist" });
var result = await userManager.GetUserIdAsync(user);
return new JsonResult(result);
}
Controller return result
"85e39a3e-8101-4166-9193-5e41bec1a7ce"
Function
private async Task Login()
{
var user = new userName { Username = Username };
var loginUser = new LoginDb { Username = Username, Password = Password };
if (Username == null || Password == null)
{
toastService.ShowWarning("Please enter Username and Password");
}
else
{
user = await Http.GetFromJsonAsync<userName>("Authentication/UserId?Username=" + Username);
if (user != null)
{
string Id = System.Text.Json.JsonSerializer.Serialize(user);
var result = await Http.PostAsJsonAsync("Authentication/login", loginUser);
if (result.IsSuccessStatusCode)
{
NavigationManager.NavigateTo("/profile/" + Id);
toastService.ShowSuccess("Login successful");
}
else
{
toastService.ShowError("Username or Password is wrong");
}
}
else
{
NavigationManager.NavigateTo("/login");
}
}
}
OK, I can see a few problems.
On the Server:
[HttpGet]
[Route("UserId")]
public async Task<ActionResult<ApplicationUser>> GetUserId(string Username) // A
{
var user = await userManager.FindByNameAsync(Username);
if (user == null) // B
return StatusCode(StatusCodes.Status500InternalServerError, new Response { Status = "Error", Message = "User not exist" });
var result = await userManager.GetUserIdAsync(user);
return new JsonResult(result);
}
First, your return type here is Task<ActionResult<ApplicationUser>> . ApplicationUser is tied to the backend Identity library, you can't and shouldn't use it for a DTO.
And you don't, in the end you have return new JsonResult(result); which is OK when you change the return type to just Task<ActionResult>.
On the client:
//user = await Http.GetFromJsonAsync<userName>("Authentication/UserId?Username=" + Username);
var userId = await Http.GetFromJsonAsync<string>("Authentication/UserId?Username=" + Username);
The endpoint returns a simple string. Json does not know about 'UserName' or anything else.
//string Id = System.Text.Json.JsonSerializer.Serialize(user); -- use UserId
You are serializing the Id (again) here, making it almost certainly invalid for an URL. So just skip that.
Related
I have a set of API's that I want to put some authentication on. I have added the authorization and authentication pieces to the project. I have added the context for the database and the application user. I can create users and log them and in and return JWT to the caller and validate the users based on the JWT. However, there are certain users that I want to create that are admins that will have elevated privileges. Here is the code I am user to Create a user:
async Task<Response> ICreateUser.CreateUser(RegisterModel model)
{
var userExists = await userManager.FindByNameAsync(model.UserName);
if (userExists != null)
{
return new Response { Status = "error", Message = "User already exists" };
}
ApplicationUser user = new ApplicationUser()
{
Email = model.Email,
SecurityStamp = Guid.NewGuid().ToString(),
UserName = model.UserName
};
var result = await userManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return new Response { Status = "Error", Message = "Unable to create user" };
}
else
{
var adminRole = await roleManager.FindByNameAsync("admin");
if(!await userManager.IsInRoleAsync(user, adminRole.Name))
{
await userManager.AddToRoleAsync(user, adminRole.Name);
}
}
return new Response { Status = "Success", Message = "User Created" };
}
This will add the user, and even add them to the role. But when I do a list on the claims all I see are the nameidentifier, jti, email, exp, iss, and aud values. Here is the code I am using to return the claims:
public IActionResult Index()
{
var claims = User.Claims.Select(claim => new { claim.Type, claim.Value }).ToArray();
return Json(claims);
}
When I created the Role for the admin I used this code:
public async Task<IActionResult> Create([Required] string name)
{
var adminRole = await roleManager.FindByNameAsync(name);
if (adminRole == null)
{
adminRole = new IdentityRole(name);
await roleManager.CreateAsync(adminRole);
await roleManager.AddClaimAsync(adminRole, new Claim(ClaimTypes.Role, name));
return Ok("Role Created");
}
else
{
return StatusCode(StatusCodes.Status500InternalServerError, new Response { Status = "error", Message = "Role Not created" });
}
}
Like I said, I can create the user, but I don't see the Admin claim added to user so I can't authenticate by the role. What am I missing?
When I created the JWT token I needed to add a call to GetRolesAsync. Once I got this list, I could loop through the array and add the claims.
var claim = new List<Claim>();
claim.Add(new Claim(JwtRegisteredClaimNames.Sub, user.UserName));
claim.Add(new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()));
claim.Add(new Claim(ClaimTypes.Email, model.Email));
var roles = userManager.GetRolesAsync(user).Result.ToArray();
foreach(var role in roles)
{
claim.Add(new Claim(ClaimTypes.Role, role));
}
This bit of code allows me to add the user to the roles they are assigned to when they are created.
How can I force to log in a non-existing user?
[HttpPost]
[UnitOfWork]
public virtual async Task<JsonResult> Login(LoginViewModel loginModel, string returnUrl = "", string returnUrlHash = "")
{
returnUrl = NormalizeReturnUrl(returnUrl);
if (!string.IsNullOrWhiteSpace(returnUrlHash))
{
returnUrl = returnUrl + returnUrlHash;
}
var loginResult = await GetLoginResultAsync(loginModel.UsernameOrEmailAddress, loginModel.Password, GetTenancyNameOrNull());
//await _signInManager.SignInAsync(loginResult.Identity, loginModel.RememberMe);
//ClaimsIdentity identity=new ClaimsIdentity();
//identity.Name = "inanc";
Authorization.Users.User usr=new User();
usr.UserName = "inanc";
usr.Id = 12;
await _signInManager.SignInAsync(usr, false);
await UnitOfWorkManager.Current.SaveChangesAsync();
return Json(new AjaxResponse { TargetUrl = returnUrl });
}
Forexample this is not working.This throws an error.How can I force to sign in a non existing user.
I'm developing a website which uses AngularJS in the frontend and ASP.NET web API in the backend. I'm trying to configure external logins(Facebook) for my site. I have already enabled Cors on the API. The order of API calls are:
API call to
api/Account/ExternalLogins?returnUrl=%2F&generateState=true
to get a list of external login providers.
This returns
[{"name":"Facebook",
"url":"/api/Account/ExternalLogin?provider=Facebook&response_type=token&client_id=self&redirect_uri=http%3A%2F%2Flocalhost%3A15359%2F&state=xxxxxxxxxx",
"state":"xxxxxxxxxx"}]
Now I send a GET request to url returned earlier. This triggers a preflight request to https://www.facebook.com/dialog/oauth?response_type=code&client_id=xxxxxxx&redirect_uri=https%3A%2F%2Flocalhost%3A44327%2Fsignin-facebook&scope=manage_pages&state=xxxxxxx which gives error. This is never redirected to Facebook Login Page.
Both the request and response headers for /api/Account/ExternalLogin?provider=Facebook&response_type=token&client_id=self&redirect_uri=http%3A%2F%2Flocalhost%3A15359%2F&state=xxxxxxxxxx contains Access-Control-Allow-Origin:*
But for the preflight request https://www.facebook.com/dialog/oauth?response_type=code&client_id=xxxxxxx&redirect_uri=https%3A%2F%2Flocalhost%3A44327%2Fsignin-facebook&scope=manage_pages&state=xxxxxxx Access-Control-Allow-Origin header is missing.
The code snippets are mentioned below.
app.js
$httpProvider.defaults.headers.common['Access-Control-Allow-Origin'] = '*';
$httpProvider.defaults.headers.common['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, Content-Length, X-Requested-With';
$httpProvider.defaults.headers.common['Access-Control-Allow-Credentials'] = true;
$httpProvider.defaults.headers.common['Access-Control-Allow-Method'] = 'GET, PUT, POST, DELETE, OPTIONS';
Start.Auth.cs
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
app.UseCors(CorsOptions.AllowAll);
// 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
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/api/Account/ExternalLogin"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
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("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
//Provider = new AuthorizationServerProvider()
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
// Enables the application to remember the second login verification factor such as phone or email.
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
// This is similar to the RememberMe option when you log in.
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions
{
AppId = "xxxxxxxxx",
AppSecret = "xxxxxxxxx",
BackchannelHttpHandler = new FacebookBackChannelHandler(),
Provider = new FacebookAuthenticationProvider()
{
OnAuthenticated = (context) =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken));
return Task.FromResult(0);
}
},
SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie,
SendAppSecretProof = true
};
facebookOptions.Scope.Add(ConfigurationManager.AppSettings["Facebook_Scope"]);
facebookOptions.AuthenticationMode = AuthenticationMode.Passive;
app.UseFacebookAuthentication(facebookOptions);
AccountController
[Authorize]
[EnableCors(origins: "*", headers: "*", methods: "*")]
[RoutePrefix("api/Account")]
public class AccountController : ApiController
{
private const string LocalLoginProvider = "Local";
private ApplicationUserManager _userManager;
public AccountController()
{
}
public AccountController(ApplicationUserManager userManager,
ISecureDataFormat<AuthenticationTicket> accessTokenFormat)
{
UserManager = userManager;
AccessTokenFormat = accessTokenFormat;
}
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
public ISecureDataFormat<AuthenticationTicket> AccessTokenFormat { get; private set; }
// GET api/Account/UserInfo
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("UserInfo")]
public UserInfoViewModel GetUserInfo()
{
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
return new UserInfoViewModel
{
Email = User.Identity.GetUserName(),
HasRegistered = externalLogin == null,
LoginProvider = externalLogin != null ? externalLogin.LoginProvider : null
};
}
// POST api/Account/Logout
[Route("Logout")]
[AllowAnonymous]
public IHttpActionResult Logout()
{
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
return Ok();
}
// POST api/Account/AddExternalLogin
[Route("AddExternalLogin")]
public async Task<IHttpActionResult> AddExternalLogin(AddExternalLoginBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
AuthenticationTicket ticket = AccessTokenFormat.Unprotect(model.ExternalAccessToken);
if (ticket == null || ticket.Identity == null || (ticket.Properties != null
&& ticket.Properties.ExpiresUtc.HasValue
&& ticket.Properties.ExpiresUtc.Value < DateTimeOffset.UtcNow))
{
return BadRequest("External login failure.");
}
ExternalLoginData externalData = ExternalLoginData.FromIdentity(ticket.Identity);
if (externalData == null)
{
return BadRequest("The external login is already associated with an account.");
}
IdentityResult result = await UserManager.AddLoginAsync(User.Identity.GetUserId(),
new UserLoginInfo(externalData.LoginProvider, externalData.ProviderKey));
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// GET api/Account/ExternalLogin
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]
[AllowAnonymous]
[Route("ExternalLogin", Name = "ExternalLogin")]
public async Task<IHttpActionResult> GetExternalLogin(string provider, string error = null)
{
if (error != null)
{
return Redirect(Url.Content("~/") + "#error=" + Uri.EscapeDataString(error));
}
if (!User.Identity.IsAuthenticated)
{
return new ChallengeResult(provider, this);
}
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
if (externalLogin == null)
{
return InternalServerError();
}
if (externalLogin.LoginProvider != provider)
{
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
return new ChallengeResult(provider, this);
}
ApplicationUser user = await UserManager.FindAsync(new UserLoginInfo(externalLogin.LoginProvider,
externalLogin.ProviderKey));
bool hasRegistered = user != null;
if (hasRegistered)
{
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(UserManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookieIdentity = await user.GenerateUserIdentityAsync(UserManager,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.UserName);
Authentication.SignIn(properties, oAuthIdentity, cookieIdentity);
}
else
{
IEnumerable<Claim> claims = externalLogin.GetClaims();
ClaimsIdentity identity = new ClaimsIdentity(claims, OAuthDefaults.AuthenticationType);
Authentication.SignIn(identity);
}
return Ok();
}
// GET api/Account/ExternalLogins?returnUrl=%2F&generateState=true
[AllowAnonymous]
[Route("ExternalLogins")]
public IEnumerable<ExternalLoginViewModel> GetExternalLogins(string returnUrl, bool generateState = false)
{
IEnumerable<AuthenticationDescription> descriptions = Authentication.GetExternalAuthenticationTypes();
List<ExternalLoginViewModel> logins = new List<ExternalLoginViewModel>();
string state;
if (generateState)
{
const int strengthInBits = 256;
state = RandomOAuthStateGenerator.Generate(strengthInBits);
}
else
{
state = null;
}
foreach (AuthenticationDescription description in descriptions)
{
ExternalLoginViewModel login = new ExternalLoginViewModel
{
Name = description.Caption,
Url = Url.Route("ExternalLogin", new
{
provider = description.AuthenticationType,
response_type = "token",
client_id = Startup.PublicClientId,
redirect_uri = new Uri(Request.RequestUri, returnUrl).AbsoluteUri,
state = state
}),
State = state
};
logins.Add(login);
}
return logins;
}
// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// POST api/Account/RegisterExternal
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("RegisterExternal")]
public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var info = await Authentication.GetExternalLoginInfoAsync();
if (info == null)
{
return InternalServerError();
}
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
result = await UserManager.AddLoginAsync(user.Id, info.Login);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
protected override void Dispose(bool disposing)
{
if (disposing && _userManager != null)
{
_userManager.Dispose();
_userManager = null;
}
base.Dispose(disposing);
}
}
I know this is achievable using MVC Account Controller. I'm looking for a way to do this entirely using web api with no dependency on MVC.
Thanks!
I want to get specific data from a action in a webAPI controller to my windows mobile app .here is my webAPI action;
// GET: api/Customer/5
[ResponseType(typeof(Customer))]
public IHttpActionResult GetValidCustomer(string username,string password)
{
var customer = (from cust in db.Customers
where cust.CustomerName == username && cust.CustomerPw == password
select cust).ToList();
if (customer == null)
{
return NotFound();
}
else
{
return Ok(customer);
}
}
I have tried to consume that action as follows,but the windows emulator starts to freeze when I use that method.
public async System.Threading.Tasks.Task<bool> isValidUser(string username,string password)
{
try
{
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:2335");
var url = "api/Customer?username="+username+"&password="+password;
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
}
else
{
}
}
}
catch (Exception ex)
{
return false;
}
}
I want to send private message to Twitter with my web app in asp.net mvc3. I was doing the authorization with oauth, here is my code:
in AccountController:
public ActionResult LogOn()
{
credentials.ConsumerKey = TwitterClient.ConsumerKey;
credentials.ConsumerSecret = TwitterClient.ConsumerSecret;
auth = new MvcAuthorizer { Credentials = credentials };
auth.CompleteAuthorization(Request.Url);
if (!auth.IsAuthorized)
{
string callbackUrl = "http://127.0.0.1:31891/Account/CompleteAuth";
Uri uri = new Uri(callbackUrl);
return auth.BeginAuthorization(uri);
}
return RedirectToAction("Index", "Home");
}
After the user is authorized , he is redirect to action CompleteAuth, and I get the token and tokenSecret, here is code of this action:
public ActionResult CompleteAuth(string oauth_token, string oauth_verifier)
{
string AccessToken = oauth_token;
string AccessTokenSecret = oauth_verifier;
TempData["AccessToken"] = AccessToken;
TempData["TokenSecret"] = AccessTokenSecret;
return RedirectToAction("Tweeting","Home");
}
after, it's redirect to Home in action Tweeting, when i try to get userId and send to him direct message :
public ActionResult Tweeting()
{
var auth = new MvcAuthorizer
{
Credentials = new InMemoryCredentials()
{
ConsumerKey = TwitterClient.ConsumerKey,
ConsumerSecret = TwitterClient.ConsumerSecret,
//OAuthToken = (string)Session["AccessToken"],
//AccessToken = Session["TokenSecret"]
OAuthToken = TempData["AccessToken"] as string,
AccessToken = TempData["TokenSecret"] as string
}
};
var twitterContext = new TwitterContext(auth);
var message = twitterContext.NewDirectMessage(auth.UserId, "Hi ucef, cool to discuss with you" + DateTime.Now);
return View();
}
But exception occurred because auth.UserId is null, have you any idea?
This appears to be the same as your previous question:
Send Private message with LinqToTwitter
Joe