namespace Acme.Application.Authorization
{
using System;
using System.Security.Claims;
/// <summary>
/// Represents an action that can be performed on a resource.
/// </summary>
public interface IResourceAction
{
/// <summary>
/// Creates a claim corresponding to this action.
/// </summary>
/// <returns>
/// A claim that the principal is allowed to perform the action
/// defined by this object.
/// </returns>
Claim ToClaim();
/// <summary>
/// Gets the action name.
/// </summary>
string Action { get; }
/// <summary>
/// Gets the resource name.
/// </summary>
string Resource { get; }
}
/// <summary>
/// Represents an action that can be performed on a resource.
/// </summary>
/// <remarks>
/// The declaring class of a concrete descendant of this class
/// specifies the resource.
/// </remarks>
/// <typeparam name="TAction">
/// A class representing a concrete action.
/// </typeparam>
public abstract class ResourceAction<TAction> : IResourceAction
where TAction : IResourceAction, new()
{
/// <summary>
/// A claim corresponding to this action.
/// </summary>
public static Claim Claim = new TAction().ToClaim();
/// <summary>
/// Gets the action name.
/// </summary>
public string Action
{
get
{
return GetType().Name.ToLowerInvariant();
}
}
/// <summary>
/// Gets the resource name.
/// </summary>
public string Resource
{
get
{
Type resourceType = GetType().DeclaringType;
if (resourceType == null)
{
throw new InvalidOperationException(
"The resource type could not be determined from the action type.");
}
return ResourceAuthorization.Resource.Prefix + resourceType.Name.ToLowerInvariant();
}
}
/// <summary>
/// Creates a claim corresponding to this action.
/// </summary>
/// <returns>
/// A claim that the principal is allowed to perform the action defined by this object.
/// </returns>
public Claim ToClaim()
{
return new Claim(Resource, Action);
}
}
/// <summary>
/// Defines available resources and their corresponding actions.
/// </summary>
/// <remarks>
/// <example>
/// Adding claims
/// <code>
/// identity.AddClaim(Resource.Missiles.Launch.Claim);
/// </code>
/// </example>
/// <example>
/// Requiring permissions declaratively
/// <code>
/// [ResourceAuthorize(typeof(Resource.Missiles.Launch))]
/// public void ControllerAction() {}
/// </code>
/// </example>
/// </remarks>
public static class Resource
{
/// <summary>
/// The standard prefix of resource names.
/// </summary>
public const string Prefix = "acme:resouce:";
/// <summary>
/// Nuclear missiles.
/// </summary>
public static class Missiles
{
/// <summary>
/// The user may launch missiles.
/// </summary>
public sealed class Launch : ResourceAction<Launch>
{
}
}
}
/*
public class ResourceAuthorizeAttribute : AuthorizeAttribute
{
private readonly string _action;
private readonly string _resource;
/// <summary>
/// Initializes a new instance of <see cref="ResourceAuthorizeAttribute"/>
/// with the specified resource and acrion.
/// </summary>
/// <param name="resourceActionType">
/// The type describing the resource-action pair.
/// Must be of the form <c>Resource.YourResource.YourAction</c>.
/// See the nested classes of the <see cref="Resource"/> class.
/// </param>
public ResourceAuthorizeAttribute(Type resourceActionType)
{
var ra = (IResourceAction)Activator.CreateInstance(resourceActionType);
_action = ra.Action;
_resource = ra.Resource;
}
...
}
*/
}