采用ASP.NET Web API 提供的IAuthenticationFilter和IAuthorizationFilter接口分別實現驗證和授權。其中用到IIdentity和IPrincipal接口。
IIdentity的具體類型用來標識通過驗證的用戶身份,由用戶憑據(Credential)來創建一個指定名稱的用戶。
接口定義:
//定義標識對象的基本功能。
public interface IIdentity
{
// 獲取所使用的身份驗證的類型。
string AuthenticationType { get; }
// 獲取一個值,該值指示是否驗證了用戶。
bool IsAuthenticated { get; }
// 獲取當前用戶的名稱
string Name { get; }
}
不同的驗證類型,對IIdentity有不同的實現方式。如:WindowsIdentity(Windows集成)、FormsIdentity(Forms)和GenericIdentity(一般用戶)等。
如果自定義實現驗證方式,可以采用GenericIdentity來標識用戶身份,已通過驗證的用戶是一個指定名稱的GenericIdentity。
GenericIdentity類型定義:
public class GenericIdentity : ClaimsIdentity
{
// 使用指定的 System.Security.Principal.GenericIdentity 對象初始化 System.Security.Principal.GenericIdentity
// 類的新實例。
protected GenericIdentity(GenericIdentity identity);
// 初始化 System.Security.Principal.GenericIdentity 類的新實例,該類表示具有指定名稱的用戶。
public GenericIdentity(string name);
// 初始化 System.Security.Principal.GenericIdentity 類的新實例,該類表示具有指定名稱和身份驗證類型的用戶。
public GenericIdentity(string name, string type);
// 獲取用於標識用戶的身份驗證的類型。
public override string AuthenticationType { get; }
// 為用戶獲取此最常用標識表示的所有聲明。
public override IEnumerable<Claim> Claims { get; }
// 獲取一個值,該值指示是否驗證了用戶。
public override bool IsAuthenticated { get; }
// 獲取用戶的名稱。
public override string Name { get; }
// 創建作為當前實例副本的新對象。
public override ClaimsIdentity Clone();
}
IPrincipal的具體類型表示一個已通過驗證並獲得授權的對象。
接口定義:
public interface IPrincipal
{
// 獲取當前用戶的標識。
IIdentity Identity { get; }
// 確定當前用戶是否屬於指定的角色。
bool IsInRole(string role);
}
GenericPrincipal類型,用用戶標識和角色名稱數組來初始化。
public class GenericPrincipal : ClaimsPrincipal
{
// 從用戶標識和角色名稱數組(標識表示的用戶屬於該數組)初始化 System.Security.Principal.GenericPrincipal
// 類的新實例。
public GenericPrincipal(IIdentity identity, string[] roles);
// 獲取當前 System.Security.Principal.GenericPrincipal 表示的用戶的 System.Security.Principal.GenericIdentity。
public override IIdentity Identity { get; }
// 確定當前 System.Security.Principal.GenericPrincipal 是否屬於指定的角色。
public override bool IsInRole(string role);
}
IAuthenticationFilter接口定義:
public interface IAuthenticationFilter : IFilter
{
Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken);
Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken);
}
其中AuthenticateAsync方法用於實現用戶認證,而ChallengeAsync方法在認證失敗的情況下,生成“質詢(Challenge)”結果。
用自定義AuthenticateAttribute類型實現Basic認證:
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)]
public class AuthenticateAttribute : FilterAttribute, IAuthenticationFilter
{
private static readonly Dictionary<string, string> UserAccount;
static AuthenticateAttribute()
{
UserAccount = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{"CHN", "china"}
};
}
public Task AuthenticateAsync(HttpAuthenticationContext context,
System.Threading.CancellationToken cancellationToken)
{
var headerValue = context.Request.Headers.Authorization;
if (null == headerValue || headerValue.Scheme != "Basic")
return Task.Factory.StartNew(() => { }, cancellationToken);
var byteArray = Convert.FromBase64String(headerValue.Parameter);
var credential = Encoding.UTF8.GetString(byteArray);
var split = credential.Split(':');
if (split.Length != 2) return Task.Factory.StartNew(() => { }, cancellationToken);
var userName = split[0];
string password;
if (!UserAccount.TryGetValue(userName, out password))
return Task.Factory.StartNew(() => { }, cancellationToken);
if (password != split[1]) return Task.Factory.StartNew(() => { }, cancellationToken);
var identity=new GenericIdentity(userName);
IPrincipal user = new GenericPrincipal(identity,new string[0]);
context.Principal = user;
return Task.FromResult<object>(null);
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context,
System.Threading.CancellationToken cancellationToken)
{
var user = context.ActionContext.ControllerContext.RequestContext.Principal;
if (null != user && user.Identity.IsAuthenticated)
return Task.Factory.StartNew(() => { }, cancellationToken);
var parameter = string.Format("realm=\"{0}\"", context.Request.RequestUri.DnsSafeHost);
var challenge=new AuthenticationHeaderValue(
"Basic",parameter);
context.Result=new UnauthorizedResult(new[]{challenge},
context.Request);
return Task.FromResult<object>(null);
}
}