我有一个使用个人身份验证的MVC5应用程序,当然还有ASP.NET身份.关键是我扩展了我有一个继承自ApplicationUser的模型,它只是这样定义:
public class NormalUser : ApplicationUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
所以,重点是,首先我想检查是否有登录用户,如果有,我想获得他/她的FirstName,LastName和Email字段.我怎样才能实现它?
我想我需要使用这样的东西来检查是否有登录用户:
if (Request.IsAuthenticated)
{
...
}
Run Code Online (Sandbox Code Playgroud)
但是,如何为当前用户获取这些特定字段的值?
在MVC5中,用户数据默认存储在会话中,并且根据请求将数据解析为ClaimsPrincipal包含用户名(或id)和声明的数据.
这是我选择实现它的方式,它可能不是最简单的解决方案,但它确实使它易于使用.
用法示例:
在控制器中:
public ActionResult Index()
{
ViewBag.ReverseDisplayName = this.User.LastName + ", " + this.User.FirstName;
}
Run Code Online (Sandbox Code Playgroud)
在视图中或_Layout:
@if(User.IsAuthenticated)
{
<span>@User.DisplayName</span>
}
Run Code Online (Sandbox Code Playgroud)
1.替换ClaimsIdentityFactory
using System.Security.Claims;
using System.Threading.Tasks;
using Domain.Models;
using Microsoft.AspNet.Identity;
public class AppClaimsIdentityFactory : IClaimsIdentityFactory<User, int>
{
internal const string IdentityProviderClaimType = "http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider";
internal const string DefaultIdentityProviderClaimValue = "My Identity Provider";
/// <summary>
/// Constructor
/// </summary>
public AppClaimsIdentityFactory()
{
RoleClaimType = ClaimsIdentity.DefaultRoleClaimType;
UserIdClaimType = ClaimTypes.NameIdentifier;
UserNameClaimType = ClaimsIdentity.DefaultNameClaimType;
SecurityStampClaimType = Constants.DefaultSecurityStampClaimType;
}
/// <summary>
/// Claim type used for role claims
/// </summary>
public string RoleClaimType { get; set; }
/// <summary>
/// Claim type used for the user name
/// </summary>
public string UserNameClaimType { get; set; }
/// <summary>
/// Claim type used for the user id
/// </summary>
public string UserIdClaimType { get; set; }
/// <summary>
/// Claim type used for the user security stamp
/// </summary>
public string SecurityStampClaimType { get; set; }
/// <summary>
/// Create a ClaimsIdentity from a user
/// </summary>
/// <param name="manager"></param>
/// <param name="user"></param>
/// <param name="authenticationType"></param>
/// <returns></returns>
public virtual async Task<ClaimsIdentity> CreateAsync(UserManager<User, int> manager, User user, string authenticationType)
{
if (manager == null)
{
throw new ArgumentNullException("manager");
}
if (user == null)
{
throw new ArgumentNullException("user");
}
var id = new ClaimsIdentity(authenticationType, UserNameClaimType, RoleClaimType);
id.AddClaim(new Claim(UserIdClaimType, user.Id.ToString(), ClaimValueTypes.String));
id.AddClaim(new Claim(UserNameClaimType, user.UserName, ClaimValueTypes.String));
id.AddClaim(new Claim(IdentityProviderClaimType, DefaultIdentityProviderClaimValue, ClaimValueTypes.String));
id.AddClaim(new Claim(ClaimTypes.Email, user.EmailAddress));
if (user.ContactInfo.FirstName != null && user.ContactInfo.LastName != null)
{
id.AddClaim(new Claim(ClaimTypes.GivenName, user.ContactInfo.FirstName));
id.AddClaim(new Claim(ClaimTypes.Surname, user.ContactInfo.LastName));
}
if (manager.SupportsUserSecurityStamp)
{
id.AddClaim(new Claim(SecurityStampClaimType,
await manager.GetSecurityStampAsync(user.Id)));
}
if (manager.SupportsUserRole)
{
user.Roles.ToList().ForEach(r =>
id.AddClaim(new Claim(ClaimTypes.Role, r.Id.ToString(), ClaimValueTypes.String)));
}
if (manager.SupportsUserClaim)
{
id.AddClaims(await manager.GetClaimsAsync(user.Id));
}
return id;
}
Run Code Online (Sandbox Code Playgroud)
2.更改UserManager以使用它
public static UserManager<User,int> Create(IdentityFactoryOptions<AppUserManager> options, IOwinContext context)
{
var manager = new UserManager<User,int>(new UserStore<User,int>(new ApplicationDbContext()))
{
ClaimsIdentityFactory = new AppClaimsIdentityFactory()
};
// more initialization here
return manager;
}
Run Code Online (Sandbox Code Playgroud)
3.创建新自定义 Principal
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Security.Claims;
public class UserPrincipal : ClaimsPrincipal
{
public UserPrincipal(ClaimsPrincipal principal)
: base(principal.Identities)
{
}
public int UserId
{
get { return FindFirstValue<int>(ClaimTypes.NameIdentifier); }
}
public string UserName
{
get { return FindFirstValue<string>(ClaimsIdentity.DefaultNameClaimType); }
}
public string Email
{
get { return FindFirstValue<string>(ClaimTypes.Email); }
}
public string FirstName
{
get { return FindFirstValue<string>(ClaimTypes.GivenName); }
}
public string LastName
{
get { return FindFirstValue<string>(ClaimTypes.Surname); }
}
public string DisplayName
{
get
{
var name = string.Format("{0} {1}", this.FirstName, this.LastName).Trim();
return name.Length > 0 ? name : this.UserName;
}
}
public IEnumerable<int> Roles
{
get { return FindValues<int>(ClaimTypes.Role); }
}
private T FindFirstValue<T>(string type)
{
return Claims
.Where(p => p.Type == type)
.Select(p => (T)Convert.ChangeType(p.Value, typeof(T), CultureInfo.InvariantCulture))
.FirstOrDefault();
}
private IEnumerable<T> FindValues<T>(string type)
{
return Claims
.Where(p => p.Type == type)
.Select(p => (T)Convert.ChangeType(p.Value, typeof(T), CultureInfo.InvariantCulture))
.ToList();
}
}
Run Code Online (Sandbox Code Playgroud)
4.创建一个AuthenticationFilter以使用它
using System.Security.Claims;
using System.Web.Mvc;
using System.Web.Mvc.Filters;
public class AppAuthenticationFilterAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
//This method is responsible for setting and modifying the principle for the current request though the filterContext .
//Here you can modify the principle or applying some authentication logic.
var principal = filterContext.Principal as ClaimsPrincipal;
if (principal != null && !(principal is UserPrincipal))
{
filterContext.Principal = new UserPrincipal(principal);
}
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
//This method is responsible for validating the current principal and permitting the execution of the current action/request.
//Here you should validate if the current principle is valid / permitted to invoke the current action. (However I would place this logic to an authorization filter)
//filterContext.Result = new RedirectToRouteResult("CustomErrorPage",null);
}
}
Run Code Online (Sandbox Code Playgroud)
5.注册auth过滤器以全局加载 FilterConfig
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new AppAuthenticationFilterAttribute());
}
Run Code Online (Sandbox Code Playgroud)
到现在Principal为止,我们还剩下要做的就是在Controller和View中公开它.
6.创建控制器基类
public abstract class ControllerBase : Controller
{
public new UserPrincipal User
{
get { return HttpContext.User as UserPrincipal; }
}
}
Run Code Online (Sandbox Code Playgroud)
7.创建WebViewPage基类并修改web.config以使用它
public abstract class BaseViewPage : WebViewPage
{
public virtual new UserPrincipal User
{
get { return base.User as UserPrincipal; }
}
public bool IsAuthenticated
{
get { return base.User.Identity.IsAuthenticated; }
}
}
public abstract class BaseViewPage<TModel> : WebViewPage<TModel>
{
public virtual new UserPrincipal User
{
get { return base.User as UserPrincipal; }
}
public bool IsAuthenticated
{
get { return base.User.Identity.IsAuthenticated; }
}
}
Run Code Online (Sandbox Code Playgroud)
和文件夹web.config里面Views:
<pages pageBaseType="MyApp.Web.Views.BaseViewPage">
Run Code Online (Sandbox Code Playgroud)
重要!
不要存储太多数据,Principal因为这些数据在每个请求上来回传递.
是的,在身份中,如果您需要其他用户信息,您只需从数据库中提取用户,因为这些信息现在都存储在实际的用户对象上。
if (Request.IsAuthenticated)
{
var user = UserManager.FindById(User.Identity.GetUserId());
}
Run Code Online (Sandbox Code Playgroud)
如果GetUserId未开启User.Identity,请将以下内容添加到您的使用中:
using Microsoft.AspNet.Identity;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4683 次 |
| 最近记录: |