问题
What I Need?! I have an ASP.NET identity system setup and running with external logins. For whatever reason i need to setup a custom authentication after the ASP.NET identity authentication. Let me explain how? Lets say I have three pages for the users to view on my application, Page A,B,C. Who can view Page A? Any anonymous user can view page A. Who can view Page A & B? Any user who have created an account either with his/her email & password or with external logins. Who can view Page A,B & C?
Here is the place i want to set custom authentication. Any user who have created an account either with his/her email account or external logins AND has a valid serial key. Serial Key? I set a class in ASP.NET identity as below:
public class UserDetails : IdentityUser
{
public virtual MembershipSerial MembershipSerial { get; set; }
}
public class MembershipSerial
{
[HiddenInput(DisplayValue=false)]
public int Id { get; set; }
[HiddenInput(DisplayValue=false)]
public string Serial { get; set; }
[Required]
[Display(Name="Membership Serial")]
public string SerialConfirmed { get; set; }
}
public class MyDbContext : IdentityDbContext<UserDetails>
{
public MyDbContext()
: base ("EFDbContext")
{
}
public System.Data.Entity.DbSet<MembershipSerial> MembershipSerial { get; set; }
}
As you see above class i set up three properties in the class. Field Id is for the Ids of the serials, The Serial is a 14 Alpha numeric letters which is entered by the administrator and as you can see it is a hidden field which not allowing null. The field SerialConfirmed is also a 14 Alpha Numeric letters which will be entered by the users to authenticate in order to do some certain tasks in the application. The whole concept is, that a logged in user should be pushed for a second type authentication which is authentication vs serial numbers.
I am seriously in need of help and searching online didn't help too much. If you need more information or yet its is unclear don't hesitate to ask me. Regards Edit: I am using EF code first. Dostdar
回答1:
It seems like a custom authorization attribute would work. Here's an example implementation:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class RequiresSerialValidationAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
bool hasValidSerial = false;
if (filterContext.HttpContext.Request.IsAuthenticated)
{
string userName = filterContext.HttpContext.User.Identity.Name;
if (!string.IsNullOrWhiteSpace(userName))
{
string serial = string.Empty;// TODO: Retrieve user's previously authenticated serial, perhaps from Session or a cookie?
if(!string.IsNullOrWhiteSpace(serial))
{
var service = DependencyResolver.Current.GetService<IYourAuthService>();
hasValidSerial = service.IsSerialValidForUser(userName, serial);
}
}
}
if (!hasValidSerial)
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "yourserialauthcontroller", action = "yourauthaction", area = string.Empty }));
}
else
{
base.OnAuthorization(filterContext);
}
}
}
You would decorate the action methods with this attribute:
[RequireSerialValidation]
public ActionResult SomeAction()
{
}
The attribute would trigger a redirect to your challenge action, where you prompt your user for their serial. Assuming all goes well, you store their serial somewhere (Session could work here, or create an encrypted cookie), and then redirect back to the original action. On this second attempt, you've already verified that the action is allowed, so no redirect occurs.
Your authentication service can be whatever you want it to be. In this example, I assume you're using dependency injection and that you've configured the global dependency resolver. Given that, your IYourAuthService could look like this (omitting other methods):
public IYourAuthService
{
bool IsSerialValidForUser(string userName, string serial);
}
with an implementation like so:
public YourAuthService : IYourAuthService
{
public bool IsSerialValidForUser(string userName, string serial)
{
using(var context = new YourEntityFrameworkDbContext())
{
return context.Users.Any(u => u.UserName.Equals(userName, StringComparison.OrdinalIgnoreCase) && u.Serial.Equals(serial, StringComparison.OrdinalIgnoreCase));
}
}
}
This assumes you have a table called User
(or Users
) in your database, and that UserName
and Serial
are fields on that table. StringComparison.OrdinalIgnoreCase lets you do a case-insensitive, culture-insensitive match on the strings you're attempting to compare.
来源:https://stackoverflow.com/questions/36814792/how-to-setup-a-custom-authentication-on-asp-net-mvc-identity