How to add roles to users in ASP.NET with OWIN - asp.net

I'm new in ASP.NET and I'm making a simple project to practice. I started with a simple MVC project without authentication because it adds many code that I didn't understand.
But now I want to add a membership to my sistem so I followed this guide:
http://benfoster.io/blog/aspnet-identity-stripped-bare-mvc-part-1
http://benfoster.io/blog/aspnet-identity-stripped-bare-mvc-part-2
But I don't know where I can add a role to the user entity..
My Startup class is this:
public class Startup
{
public static Func<UserManager<Usuario>> UserManagerFactory { get; private set; }
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "ApplicationCookie"
});
UserManagerFactory = () =>
{
var usermanager = new UserManager<Usuario>(new UserStore<Usuario>(new Vetpet3Context()));
usermanager.UserValidator = new UserValidator<Usuario>(usermanager)
{
AllowOnlyAlphanumericUserNames = false
};
return usermanager;
};
}
}
And I'm creating (for now) my users with this Action:
[HttpPost]
public async Task<ActionResult> Register(RegisterModel model)
{
if (!ModelState.IsValid)
{
return View();
}
var user = new Usuario
{
UserName=model.correo,
correo = model.correo
};
var result = await userManager.CreateAsync(user, model.password);
if (result.Succeeded)
{
await SignIn(user);
return RedirectToAction("index", "Home");
}
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error);
}
return View();
}
So everything works fine at this point, but I need to add different roles to the users , and this is the question, how I implement this part? I've read many guides but everyone does different things and I'm not sure how to add a role to my new users and how to claim these roles when they log in

to add role to the user after he successfully register :
if (result.Succeeded)
{
var roleResult = userManager.AddToRole(user.Id, "Admin");
await SignIn(user);
return RedirectToAction("index", "Home");
}
to check if the user in role :
userManager.IsInRole(user.Id, "Admin");
or even simpler in any ASP.NET MVC [Authorized] controller :
User.IsInRole("roleName");

Related

Get current windows user in Blazor Server

I want to get the name of the current Windows user for my Blazor Server project.
I tried it via HttpContext, which is unreliable, according to this github issue.
Then I went with the MS documentation, without success.
Still returned null for User
At this point I'm wondering if it's my incompetence or something with my whole idea of using Blazor Server for this.
This is pretty much all the code:
#page "/"
#using System.Security.Claims
#using Microsoft.AspNetCore.Components.Authorization
#inject AuthenticationStateProvider AuthenticationStateProvider
<h3>ClaimsPrincipal Data</h3>
<button #onclick="GetClaimsPrincipalData">Get ClaimsPrincipal Data</button>
<p>#_authMessage</p>
#if (_claims.Count() > 0)
{
<ul>
#foreach (var claim in _claims)
{
<li>#claim.Type: #claim.Value</li>
}
</ul>
}
<p>#_surnameMessage</p>
#code {
private string _authMessage;
private string _surnameMessage;
private IEnumerable<Claim> _claims = Enumerable.Empty<Claim>();
private async Task GetClaimsPrincipalData()
{
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
var user = authState.User;
if (user.Identity.IsAuthenticated)
{
_authMessage = $"{user.Identity.Name} is authenticated.";
_claims = user.Claims;
_surnameMessage =
$"Surname: {user.FindFirst(c => c.Type == ClaimTypes.Surname)?.Value}";
}
else
{
_authMessage = "The user is NOT authenticated.";
}
}
There is also the part from the docu with the user.Identity.Name, but since I dont even get the claims, as of now, I am lost with what to do.
Edit 1:
Startup.cs
public class CustomAuthStateProvider : AuthenticationStateProvider
{
public override Task<AuthenticationState> GetAuthenticationStateAsync()
{
var identity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, "mrfibuli"),
}, "Fake authentication type");
var user = new ClaimsPrincipal(identity);
return Task.FromResult(new AuthenticationState(user));
}
}
In your .razor file:
<AuthorizeView>
Hello, #context.User.Identity?.Name!
</AuthorizeView>
Or in your code-behind:
[Inject]
AuthenticationStateProvider? AuthenticationStateProvider { get; set; }
public string? CurrentUserName { get; set; }
protected override async Task OnInitializedAsync()
{
if (AuthenticationStateProvider is not null)
{
var authenticationState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
CurrentUserName = authenticationState.User.Identity?.Name;
}
}

I want web (MVC) and API on same database

I have a database, need web interface for administration and management (number of transactions, billing, and other administration) and to serve data from database (products) "manually" and API to serve data (products) to other bigger clients. All secured by SSL and https obviously.
I made a asp.net MVC 5 app (business logic and administration) and wanted to implement API (noob in API) for delivering data to users.
Have no idea how to implement security from MVC to API(same database).
The app is small and I can rewrite it. I'm thinking to try with core, but fear that i will be stuck with same problem.
Concrete question: What approach do I take and weather it should be in MVC 5 generation or .core (MVC 6) to be able to use one database for data, users and their authorizations?
(pushing everything true API is something I would like to avoid)
Ok, my project is done. I moved ahead on MVC 5.
(I apologize to you perfectionists, but I don't have the time now to strip unnecessary thing so I dumped whole files as they are :)
1st approach - abandoned
First I tried designing it as is recommended true the internet: .MVC solution, .DB for database and .API solution.
Conclusion - A lot of problems wit authentication and entity framework. At the end I abandoned this approach
2nd and successful approach
Just one solution .MVC
True NuGet installed .net Api, used integrated authorization extended using few tutorials (not single one worked). Note that I use ASP.NET Identity 2.0 Extending Identity Models and Using Integer Keys Instead of Strings and Implementing HTTPS Everywhere in ASP.Net MVC application.
Here are modifications and addons:
App_Start -> IdentityConfig.cs
public class ApplicationUserManager : UserManager<ApplicationUser, int>
{
// *** ADD INT TYPE ARGUMENT TO CONSTRUCTOR CALL:
public ApplicationUserManager(IUserStore<ApplicationUser, int> store)
: base(store)
{
}
public static ApplicationUserManager Create(
IdentityFactoryOptions<ApplicationUserManager> options,
IOwinContext context)
{
// *** PASS CUSTOM APPLICATION USER STORE AS CONSTRUCTOR ARGUMENT:
var manager = new ApplicationUserManager(
new ApplicationUserStore(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
// *** ADD INT TYPE ARGUMENT TO METHOD CALL:
manager.UserValidator = new UserValidator<ApplicationUser, int>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = false,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
// other code removed for brevity
manager.UserLockoutEnabledByDefault = Convert.ToBoolean(ConfigurationManager.AppSettings["UserLockoutEnabledByDefault"].ToString());
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(Double.Parse(ConfigurationManager.AppSettings["DefaultAccountLockoutTimeSpan"].ToString()));
manager.MaxFailedAccessAttemptsBeforeLockout = Convert.ToInt32(ConfigurationManager.AppSettings["MaxFailedAccessAttemptsBeforeLockout"].ToString());
// Register two factor authentication providers.
// This application uses Phone and Emails as a step of receiving a
// code for verifying the user You can write your own provider and plug in here.
// *** ADD INT TYPE ARGUMENT TO METHOD CALL:
//manager.RegisterTwoFactorProvider("PhoneCode",
// new PhoneNumberTokenProvider<ApplicationUser, int>
// {
// MessageFormat = "Your security code is: {0}"
// });
//// *** ADD INT TYPE ARGUMENT TO METHOD CALL:
//manager.RegisterTwoFactorProvider("EmailCode",
// new EmailTokenProvider<ApplicationUser, int>
// {
// Subject = "SecurityCode",
// BodyFormat = "Your security code is {0}"
// });
//manager.EmailService = new EmailService();
//manager.SmsService = new SmsService();
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
// *** ADD INT TYPE ARGUMENT TO METHOD CALL:
manager.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser, int>(
dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
}
// PASS CUSTOM APPLICATION ROLE AND INT AS TYPE ARGUMENTS TO BASE:
public class ApplicationRoleManager : RoleManager<ApplicationRole, int>
{
// PASS CUSTOM APPLICATION ROLE AND INT AS TYPE ARGUMENTS TO CONSTRUCTOR:
public ApplicationRoleManager(IRoleStore<ApplicationRole, int> roleStore)
: base(roleStore)
{
}
// PASS CUSTOM APPLICATION ROLE AS TYPE ARGUMENT:
public static ApplicationRoleManager Create(
IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
{
return new ApplicationRoleManager(
new ApplicationRoleStore(context.Get<ApplicationDbContext>()));
}
}
public class EmailService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
{
// Plug in your email service here to send an email.
return Task.FromResult(0);
}
}
public class SmsService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
{
// Plug in your sms service here to send a text message.
return Task.FromResult(0);
}
}
//This is useful if you do not want to tear down the database each time you run the application.
//public class ApplicationDbInitializer : DropCreateDatabaseAlways<ApplicationDbContext>
//This example shows you how to create a new database if the Model changes
public class ApplicationDbInitializer : DropCreateDatabaseIfModelChanges<ApplicationDbContext>
{
protected override void Seed(ApplicationDbContext context)
{
//InitializeIdentityForEF(context); //- Do not Seed - IGOR
//base.Seed(context);
}
//Create User=Admin#Admin.com with password=Admin#123456 in the Admin role
//public static void InitializeIdentityForEF(ApplicationDbContext db)
//{
// var userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
// var roleManager = HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>();
// const string name = "igor#email.mail";
// const string password = "LolLol1";
// const string roleName = "lol";
// //Create Role Admin if it does not exist
// var role = roleManager.FindByName(roleName);
// if (role == null)
// {
// role = new ApplicationRole(roleName);
// var roleresult = roleManager.Create(role);
// }
// var user = userManager.FindByName(name);
// if (user == null)
// {
// user = new ApplicationUser { UserName = name, Email = name };
// var result = userManager.Create(user, password);
// result = userManager.SetLockoutEnabled(user.Id, false);
// }
// // Add user admin to Role Admin if not already added
// var rolesForUser = userManager.GetRoles(user.Id);
// if (!rolesForUser.Contains(role.Name))
// {
// var result = userManager.AddToRole(user.Id, role.Name);
// }
//}
}
public class ApplicationSignInManager : SignInManager<ApplicationUser, int>
{
public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager) :
base(userManager, authenticationManager)
{ }
public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
{
return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
}
public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context)
{
return new ApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(), context.Authentication);
}
}
App_Start -> Startup.Auth.cs
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and role manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.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
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
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, int>(
validateInterval: TimeSpan.FromMinutes(2880),
regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager),
// Need to add THIS line because we added the third type argument (int) above:
getUserIdCallback: (claim) => int.Parse(claim.GetUserId()))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// 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);
// Uncomment the following lines to enable logging in with third party login providers
//app.UseMicrosoftAccountAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseTwitterAuthentication(
// consumerKey: "",
// consumerSecret: "");
//app.UseFacebookAuthentication(
// appId: "",
// appSecret: "");
//app.UseGoogleAuthentication(
// clientId: "",
// clientSecret: "");
// 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"), //TODO - makni ovo
AccessTokenExpireTimeSpan = TimeSpan.FromHours(1),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
}
}
//public partial class Startup
//{
// public void ConfigureAuth(IAppBuilder app)
// {
// // Enable the application to use a cookie to store information for the signed in user
// app.UseCookieAuthentication(new CookieAuthenticationOptions
// {
// ExpireTimeSpan = TimeSpan.FromHours(24),
// CookieSecure = CookieSecureOption.Never,
// CookieHttpOnly = false,
// SlidingExpiration = true,
// AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
// LoginPath = new PathString("/Account/Login")
// });
// // Use a cookie to temporarily store information about a user logging in with a third party login provider
// app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// }
//}
App_Start -> WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// TODO: Add any additional configuration code.
// Web API routes
config.MapHttpAttributeRoutes();
//config.Routes.MapHttpRoute(
// name: "getkey",
// routeTemplate: "api/ApiKeys/Get/{term}"
//);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// WebAPI when dealing with JSON & JavaScript!
// Setup json serialization to serialize classes to camel (std. Json format)
var formatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
formatter.SerializerSettings.ContractResolver =
new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
// make all web-api requests to be sent over https
config.MessageHandlers.Add(new EnforceHttpsHandler());
}
}
MySysAdmin controller that I use for initial insert and edit of roles and initial user.
public SysAdminController(ApplicationUserManager userManager,
ApplicationRoleManager roleManager)
{
UserManager = userManager;
RoleManager = roleManager;
}
private ApplicationUserManager _userManager;
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
set
{
_userManager = value;
}
}
private ApplicationRoleManager _roleManager;
public ApplicationRoleManager RoleManager
{
get
{
return _roleManager ?? HttpContext.GetOwinContext().Get<ApplicationRoleManager>();
}
private set
{
_roleManager = value;
}
}
public ActionResult RoleIndex()
{
return View(RoleManager.Roles);
}
public ActionResult RoleCreate()
{
return View();
}
[HttpPost]
public async Task<ActionResult> RoleCreate(SysAdminVM.RoleViewModel roleViewModel)
{
if (ModelState.IsValid)
{
// Use ApplicationRole, not IdentityRole:
var role = new ApplicationRole(roleViewModel.Name);
var roleresult = await RoleManager.CreateAsync(role);
if (!roleresult.Succeeded)
{
ModelState.AddModelError("", roleresult.Errors.First());
return View();
}
return RedirectToAction("RoleIndex");
}
return View();
}
public async Task<ActionResult> RoleEdit(int id)
{
if (id > 0)
{
var role = await RoleManager.FindByIdAsync(id);
if (role == null)
{
return HttpNotFound();
}
SysAdminVM.RoleViewModel roleModel = new SysAdminVM.RoleViewModel { Id = role.Id, Name = role.Name };
return View(roleModel);
}
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> RoleEdit([Bind(Include = "Name,Id")] SysAdminVM.RoleViewModel roleModel)
{
if (ModelState.IsValid)
{
var role = await RoleManager.FindByIdAsync(roleModel.Id);
role.Name = roleModel.Name;
await RoleManager.UpdateAsync(role);
return RedirectToAction("RoleIndex");
}
return View();
}
[AllowAnonymous]
public async Task<ActionResult> Initialize()
{
if (db.App.Where(x => x.Name.Contains("Initialize")).FirstOrDefault() == null)
{
await InitRoleCreate();
await InitUser();
db.App.Add(
new App { Name = "Initialize", Val = "true" }
);
db.SaveChanges();
return View();
}
return HttpNotFound();
}
private async Task InitRoleCreate()
{
var model = new List<string>()
{
"SysAdmin",
"Admin",
"User",
};
foreach (var item in model)
{
var role = new ApplicationRole(item);
await RoleManager.CreateAsync(role);
}
}
private async Task InitUser()
{
var user = new ApplicationUser
{
UserName = "HerGiz",
Email = "hergiz#outlook.com",
Name = "Igor Hermanović",
Contact = "098 185 3131",
TwoFactorEnabled = false,
LockoutEnabled = true,
EmailConfirmed = true
};
var adminResult = await UserManager.CreateAsync(user, "W7xtc2ywfb");
await UserManager.AddToRolesAsync(user.Id, "SysAdmin");
}
}
Entire API part that I need - controller and out of the box login (that is berried somewhere):
[Authorize]
public class ApiKeysController : ApiController
{
[Authorize]
[Route("api/getkey/{term}")]
public ShowFullKeyVM Get(string term)
{
if (User.Identity.IsAuthenticated == true)
{
if (!string.IsNullOrWhiteSpace(term) && (term.Length == 15 || term.Length == 16))
{
var lKey = new LKey();
var vm = lKey.Search(term);
if (vm != null)
{
return vm;
}
}
return new ShowFullKeyVM() { Error = "IMEI either is not valid :(", SearchIMEI = term };
}
return new ShowFullKeyVM() { Error = "Not Authenticated!!!", SearchIMEI = term };
}
}
Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
MvcHandler.DisableMvcResponseHeader = true;
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
App_Start.AutoMapperConfig.DefineMaps();
ModelBinders.Binders.Add(typeof(decimal), new Extensions.DecimalModelBinder());
ModelBinders.Binders.Add(typeof(decimal?), new Extensions.DecimalModelBinder());
}
Web.config
<appSettings>
<add key="UserLockoutEnabledByDefault" value="true" />
<add key="DefaultAccountLockoutTimeSpan" value="30" />
<add key="MaxFailedAccessAttemptsBeforeLockout" value="4" />
</appSettings>

ASP.NET MVC add user to his 'family' after usermanger has created/inserted him

I'm making a registration form for the head of the family. So when someone registers a user and a family is made. The user is inserted in the DB by the Usermanager. After this i want to make a new family and add the user to this family. The Problem is, that with the code below he complains that the user allready exists.
Hope you guys can help me out. :)
Family class:
public class Familie
{
public int familieId { get; set; }
public virtual Adres adres { get; set; }
public virtual ICollection<ApplicationUser> contactPersonen { get; set;}
public virtual ICollection<ApplicationUser> kinderen { get; set; }
public ApplicationUser gezinsHoofd { get; set; }
}
Controller Code:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Registreer_Ouder(ContactPersViewModelmodel)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser
{
UserName = model.email,
Email = model.email,
voorNaam = model.voorNaam,
achterNaam = model.achterNaam,
PhoneNumber = model.gsm,
PasswordHash = model.password,
};
Adres adres = new Adres
{
gemeente = db.Gemeente.Find(model.gemeente),
nummer = model.nummer,
straat = model.straat
};
Familie familie = new Familie
{
adres = adres
};
var result = await UserManager.CreateAsync(user, model.password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
var currentUser = UserManager.FindByName(user.UserName);
var roleresult = UserManager.AddToRole(currentUser.Id, "GezinsHoofd");
try {
db.Familie.Add(familie);
db.Familie.Find(familie.familieId).gezinsHoofd = user;
db.SaveChanges(); // ERROR IS HERE
}
catch(DbEntityValidationException ex)
{
// Just reading the exception for now..
throw;
}
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Bevestig uw registratie", "Om te bevestigen klik hier");
return RedirectToAction("Welkom", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
Execption:
In browser
Using ASP.NET identity is sometimes a little bit tricky... The point is that you are adding a user with UserManager.CreateAsync(user, model.password). This method adds a user to the database but there's no reference for the user in the current database context for now.
If you assign the user to an element in the model (db.Familie.Find(familie.familieId).gezinsHoofd = user), EF tries to add the user again to the database. What you need to do is to load the created user from the database and add the user to the family element:
// some code ignored for readability
try {
db.Familie.Add(familie);
// load user explicitly from database to include in the context
var dbUser = db.ApplicationUser.Find(currentUser.Id);
db.Familie.Find(familie.familieId).gezinsHoofd = dbUser;
db.SaveChanges(); // There should not be any error here :)
}
catch(DbEntityValidationException ex)
{
// Just reading the exception for now..
throw;
}

ASP.Net Identity and Google Authentication Issue

I have setup the project in Google and it gave me the appid and secret
I moved the id and secret to StartUp.Auth
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.CreatePerOwinContext<IdentityTestingDbContext>(IdentityTestingDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseGoogleAuthentication(
clientId: "*********************.apps.googleusercontent.com ",
clientSecret: "**************");
}
}
Here are the actions for external login, i am following Identity Sample Application (install-package Microsoft.AspNet.Identity.Samples -Pre).
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ExternalLogin(string provider, string returnUrl)
{
// Request a redirect to the external login provider
var challenge = new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
return challenge;
}
// Used for XSRF protection when adding external logins
private const string XsrfKey = "XsrfId";
internal class ChallengeResult : HttpUnauthorizedResult
{
public ChallengeResult(string provider, string redirectUri)
: this(provider, redirectUri, null)
{
}
public ChallengeResult(string provider, string redirectUri, string userId)
{
LoginProvider = provider;
RedirectUri = redirectUri;
UserId = userId;
}
public string LoginProvider { get; set; }
public string RedirectUri { get; set; }
public string UserId { get; set; }
public override void ExecuteResult(ControllerContext context)
{
var properties = new AuthenticationProperties { RedirectUri = RedirectUri };
if (UserId != null)
{
properties.Dictionary[XsrfKey] = UserId;
}
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
}
}
[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("Login");
}
var user = await UserManager.FindAsync(loginInfo.Login);
if (user == null)
{
user = new ApplicationUser
{
Email = loginInfo.Email,
UserName = loginInfo.DefaultUserName,
FirstName = string.Empty,
LastName = string.Empty
};
var result = await UserManager.CreateAsync(user);
if (!result.Succeeded)
{
return View("Error", result.Errors);
}
result = await UserManager.AddLoginAsync(user.Id, loginInfo.Login);
if (!result.Succeeded)
{
return View("Error", result.Errors);
}
}
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
identity.AddClaims(loginInfo.ExternalIdentity.Claims);
AuthenticationManager.SignIn(new AuthenticationProperties
{
IsPersistent = false
}, identity);
return Redirect(returnUrl ?? "/");
}
I get redirected to google but here i am getting an error. Looks like i am missing something but can't figure it out. I have been searching for almost 3 hours and couldn't find any thing to help with this issue.
Do you see any thing that i may be doing wrong?
Why redirect url in the image below is http://localhost:58286/signin-google
Following helped
http://www.asp.net/mvc/overview/security/create-an-aspnet-mvc-5-app-with-facebook-and-google-oauth2-and-openid-sign-on
Fix 1:
The authorized redirect url needs to be http://localhost:58286/signin-google, for the google setup screen shot in the above question thread. This isn't the callback method inside the accounts controller.
Fix 2:
I needed to enable Google+ API as well which i didn't during the setup

Custom form authentication / Authorization scheme in ASP.net MVC

I am trying to create a custom authentication scheme in ASP.NET MVC using form authentication. The idea that I might have different areas on the site that will be managed - approver are and general user area, and these will use different login pages, and so forth. So this is what I want to happen.
User access restricted page (right now I have it protected with a customer AuthorizeAttribute)
User is redirected to a specific login page (not the one from Web.config).
User credentials are verified (via custom databse scheme) and user logs in.
Would really appreciate any help with this!!!
This is what I what I have so far, and it doesn't work:
public class AdministratorAccountController : Controller
{
public ActionResult Login()
{
return View("Login");
}
[HttpPost]
public ActionResult Login(AdministratorAccountModels.LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
if (model.UserName == "admin" && model.Password == "pass") // This will be pulled from DB etc
{
var ticket = new FormsAuthenticationTicket(1, // version
model.UserName, // user name
DateTime.Now, // create time
DateTime.Now.AddSeconds(30), // expire time
false, // persistent
""); // user data
var strEncryptedTicket = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, strEncryptedTicket);
Response.Cookies.Add(cookie);
if (!String.IsNullOrEmpty(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);
}
[AdministratorAuthorize]
public ActionResult MainMenu()
{
return View();
}
public class AdministratorAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var authenCookie = httpContext.Request.Cookies.Get(FormsAuthentication.FormsCookieName);
if (authenCookie == null) return false;
var ticket = FormsAuthentication.Decrypt(authenCookie.Value);
var id = new FormsIdentity(ticket);
var astrRoles = ticket.UserData.Split(new[] { ',' });
var principal = new GenericPrincipal(id, astrRoles);
httpContext.User = principal;
return true;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
var model = new AdministratorAccountModels.LoginModel();
var viewData = new ViewDataDictionary(model);
filterContext.Result = new ViewResult { ViewName = "Login", ViewData = viewData };
}
}
}
I used a combination of code suggested by minus4 and my own code above to create this simplified scenario that might help someone else. I added some comments about things that confused me at first.
public class AdministratorAccountController : Controller
{
public ActionResult Login()
{
return View("Login");
}
[HttpPost]
public ActionResult Login(AdministratorAccountModels.LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
// Here you would call a service to process your authentication
if (model.UserName == "admin" && model.Password == "pass")
{
// * !!! *
// Creating a FromsAuthenticationTicket is what
// will set RequestContext.HttpContext.Request.IsAuthenticated to True
// in the AdminAuthorize attribute code below
// * !!! *
var ticket = new FormsAuthenticationTicket(1, // version
model.UserName, // user name
DateTime.Now, // create time
DateTime.Now.AddSeconds(30), // expire time
false, // persistent
""); // user data, such as roles
var strEncryptedTicket = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, strEncryptedTicket);
Response.Cookies.Add(cookie);
// Redirect back to the page you were trying to access
if (!String.IsNullOrEmpty(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);
}
[AdminAuthorize]
public ActionResult MainMenu()
{
return View();
}
public class AdminAuthorize : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.RequestContext.HttpContext.Request.IsAuthenticated)
{
// Redirect to the needed login page
// This can be pulled from config file or anything else
filterContext.HttpContext.Response.Redirect("/AdministratorAccount/Login?ReturnUrl="
+ HttpUtility.UrlEncode(filterContext.HttpContext.Request.RawUrl));
}
base.OnActionExecuting(filterContext);
}
}
}
okay here you go The Code
in there you have ActionFilters folder ( AuthAccess.cs)
Plugins Folder (security.cs (encrypt/decrypt cookie), SessionHandler.cs (all matters of login))
Controllers folder (BaseController.cs, and exampleController (show you how to use)
and the loginTable SQL file.
i use mysql so you may need to amend, also i use subsonic so my model would come from there
and would be in the empty models folder.
really simple to use will leave it up for a while for you, enjoy
nope cookie model is here sorry:
using System;
namespace TestApp.Models
{
public class CookieModel
{
public string CurrentGuid { get; set; }
public DateTime LoginTime { get; set; }
public Int32 UserLevel { get; set; }
public Int32 LoginID { get; set; }
public bool isValidLogin { get; set; }
public string realUserName { get; set; }
public string emailAddress { get; set; }
}
}
Isn't this what roles are for?
Have a look at asp.net mvc authorization using roles or have a look at roles in general
i tackled this one before i have a class i use for login
routines are login, read cookie, check cookie and they have a model that contains
name, email, id, userlevel
then you just have your own custom actionFilter
eg [CustomAuth(MinAllowedLevel=10)]
i use a baseclass for all my controllers so i can have an easier link to
all my session content and can then get info like so
var model = pictures.all().where(x => x.userid == users.ReadCookie.userID)
i will bob up the code tommorow if you want for you when im back on UK daytime
say 10 hrs i will let you have the class for all the session stuff and the
custom action filter that you can use, then all you need is a logins table with a userlevel field, best with levels of 10,20,30,40 incase you need a level between 1 and 2

Resources