Reputation: 12179
I want to get the endpoint method request context inside the attribute class.
So if I had this endpoint
[Auth]
[WebInvoke(UriTemplate ="/post",
Method = "POST",
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
public string CreatePost(var data)
And then in the class
public class Auth : Attribute
{
public bool IsAuthorised()
{
// get the request then add something to the endpoint context
Upvotes: 0
Views: 297
Reputation: 4598
Take a look at below WCF declaration.
[BasicHttpAuthorization(RequireSsl = true)]
[WebGet(UriTemplate = "")]
public IEnumerable Get()
{
.....
}
So BasicHttpAuthorization
implements Attribute
[AttributeUsage(AttributeTargets.Method)]
public class BasicHttpAuthorizationAttribute : Attribute
{
bool requireSsl = true;
public bool RequireSsl
{
get { return requireSsl; }
set { requireSsl = value; }
}
}
Now you can take a look at implementation of HttpOperationHandler.
1) If the user is not authenticated yet or provides the wrong credentials we return a HttpResponseException in the OnHandle
method. We set the status code to 401. This creates the functionality, where the browser asks for a username/password and then automatically resends the request.
2) In ParseAuthHeader
we get the username and password out of the request. You can then use this info with in your own way. For example with your own custom membership provider.
3) If the user can access this method, you create a GenericPrincipal
and assign it to HttpContext.Current.User
.
public class BasicHttpAuthorizationOperationHandler : HttpOperationHandler
{
BasicHttpAuthorizationAttribute basicHttpAuthorizationAttribute;
public BasicHttpAuthorizationOperationHandler(BasicHttpAuthorizationAttribute authorizeAttribute)
: base("response")
{
basicHttpAuthorizationAttribute = authorizeAttribute;
}
protected override HttpRequestMessage OnHandle(HttpRequestMessage input)
{
if (Authenticate(input))
{
return input;
}
else
{
var challengeMessage = new HttpResponseMessage(HttpStatusCode.Unauthorized);
challengeMessage.Headers.Add("WWW-Authenticate", "Basic");
throw new HttpResponseException(challengeMessage);
}
}
private bool Authenticate(HttpRequestMessage input)
{
if (basicHttpAuthorizationAttribute.RequireSsl && !HttpContext.Current.Request.IsSecureConnection && !HttpContext.Current.Request.IsLocal) return false;
if (!HttpContext.Current.Request.Headers.AllKeys.Contains("Authorization")) return false;
string authHeader = HttpContext.Current.Request.Headers["Authorization"];
IPrincipal principal;
if (TryGetPrincipal(authHeader, out principal))
{
HttpContext.Current.User = principal;
return true;
}
return false;
}
private bool TryGetPrincipal(string authHeader, out IPrincipal principal)
{
var creds = ParseAuthHeader(authHeader);
if (creds != null)
{
if (TryGetPrincipal(creds[0], creds[1], out principal)) return true;
}
principal = null;
return false;
}
private string[] ParseAuthHeader(string authHeader)
{
// Check this is a Basic Auth header
if (authHeader == null || authHeader.Length == 0 || !authHeader.StartsWith("Basic")) return null;
// Pull out the Credentials with are seperated by ':' and Base64 encoded
string base64Credentials = authHeader.Substring(6);
string[] credentials = Encoding.ASCII.GetString(Convert.FromBase64String(base64Credentials)).Split(new char[] { ':' });
if (credentials.Length != 2 || string.IsNullOrEmpty(credentials[0]) || string.IsNullOrEmpty(credentials[0])) return null;
// Okay this is the credentials
return credentials;
}
private bool TryGetPrincipal(string userName, string password, out IPrincipal principal)
{
// this is the method that does the authentication
// you can replace this with whatever logic you'd use, but proper separation would put the
if (userName.Equals("test") && password.Equals("test"))
{
principal = new GenericPrincipal(new GenericIdentity(userName), new string[] {"Admin", "User"});
return true;
}
else
{
principal = null;
return false;
}
}
}
Upvotes: 1