接下来,我定义了安全过滤器类,并为请求实现了自己的认证和授权逻辑。
public class BasicAuthenticationIdentity : GenericIdentity
{
public BasicAuthenticationIdentity(string name, string password)
: base(name, "Basic")
{
this.Password = password;
}
///
/// Basic Auth Password for custom authentication
///
public string Password { get; set; }
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class BasicAuthenticationFilter : AuthorizationFilterAttribute
{
bool Active = true;
public BasicAuthenticationFilter()
{ }
///
/// Overriden constructor to allow explicit disabling of this
/// filter's behavior. Pass false to disable (same as no filter
/// but declarative)
///
///
public BasicAuthenticationFilter(bool active)
{
Active = active;
}
///
/// Override to Web API filter method to handle Basic Auth check
///
///
public override void OnAuthorization(HttpActionContext actionContext)
{
if (Active)
{
var identity = ParseAuthorizationHeader(actionContext);
if (identity == null)
{
Challenge(actionContext);
return;
}
if (!OnAuthorizeUser(identity.Name, identity.Password, actionContext))
{
Challenge(actionContext);
return;
}
var principal = new GenericPrincipal(identity, null);
Thread.CurrentPrincipal = principal;
// inside of ASP.NET this is required
//if (HttpContext.Current != null)
// HttpContext.Current.User = principal;
base.OnAuthorization(actionContext);
}
}
///
/// Base implementation for user authentication - you probably will
/// want to override this method for application specific logic.
///
/// The base implementation merely checks for username and password
/// present and set the Thread principal.
///
/// Override this method if you want to customize Authentication
/// and store user data as needed in a Thread Principle or other
/// Request specific storage.
///
protected virtual bool OnAuthorizeUser(string username, string password, HttpActionContext actionContext)
{
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
return false;
return true;
}
///
/// Parses the Authorization header and creates user credentials
///
protected virtual BasicAuthenticationIdentity ParseAuthorizationHeader(HttpActionContext actionContext)
{
string authHeader = null;
var auth = actionContext.Request.Headers.Authorization;
if (auth != null && auth.Scheme == "Basic")
authHeader = auth.Parameter;
if (string.IsNullOrEmpty(authHeader))
return null;
authHeader = Encoding.Default.GetString(Convert.FromBase64String(authHeader));
var tokens = authHeader.Split(':');
if (tokens.Length < 2)
return null;
return new BasicAuthenticationIdentity(tokens[0], tokens[1]);
}
///
/// Send the Authentication Challenge request
///
void Challenge(HttpActionContext actionContext)
{
var host = actionContext.Request.RequestUri.DnsSafeHost;
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
//actionContext.Response = actionContext.Request.CreateUserNoAccessResponse();
actionContext.Response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", host));
}
}
public class MyBasicAuthenticationFilter : BasicAuthenticationFilter
{
public MyBasicAuthenticationFilter()
{ }
public MyBasicAuthenticationFilter(bool active)
: base(active)
{ }
protected override bool OnAuthorizeUser(string username, string password, HttpActionContext actionContext)
{
return true;
//MembershipHelper Members = new MembershipHelper(UmbracoContext.Current);
//if (Members.Login(username, password))
//{
// // Here you can also check against a specific member type or member group
// Members.Logout();
// return true;
//}
//return false;
}
}
[MyBasicAuthenticationFilter]
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class TestController : ApiController
{
public List<string> Get()
{
return new List<string>() { "Value 1", "Value 2" };
}
}
var authHeaders = {};
authHeaders.Authorization = 'Basic ' + atob(username + ":" + password);
$.ajax({
url: "http://localhost:49501/api/values",
type: "GET",
headers: authHeaders,
success: function (response) {
}
});