Skip to content

Commit 43133f1

Browse files
committed
reworked based on comments, added sample using Autofac IOC container to demonstrate usage
1 parent 668fc6c commit 43133f1

23 files changed

+646
-44
lines changed

Microsoft.Owin.Security.Authorization.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi Custom Handler", "sa
3636
EndProject
3737
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi SelfHost", "samples\WebApi SelfHost\WebApi SelfHost.csproj", "{7CCE795D-D98C-41E7-834E-64A2D7B2D1DF}"
3838
EndProject
39+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi Autofac", "samples\WebApi Autofac\WebApi Autofac.csproj", "{D91FE09B-BFBB-4F96-ADAF-2D60716793F2}"
40+
EndProject
3941
Global
4042
GlobalSection(SolutionConfigurationPlatforms) = preSolution
4143
Debug|Any CPU = Debug|Any CPU
@@ -86,6 +88,10 @@ Global
8688
{7CCE795D-D98C-41E7-834E-64A2D7B2D1DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
8789
{7CCE795D-D98C-41E7-834E-64A2D7B2D1DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
8890
{7CCE795D-D98C-41E7-834E-64A2D7B2D1DF}.Release|Any CPU.Build.0 = Release|Any CPU
91+
{D91FE09B-BFBB-4F96-ADAF-2D60716793F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
92+
{D91FE09B-BFBB-4F96-ADAF-2D60716793F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
93+
{D91FE09B-BFBB-4F96-ADAF-2D60716793F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
94+
{D91FE09B-BFBB-4F96-ADAF-2D60716793F2}.Release|Any CPU.Build.0 = Release|Any CPU
8995
EndGlobalSection
9096
GlobalSection(SolutionProperties) = preSolution
9197
HideSolutionNode = FALSE
@@ -102,5 +108,6 @@ Global
102108
{43DBB1B1-539B-4740-9CC8-998A742C598A} = {E1616215-7BD6-43BC-BFB8-D2BFD8BCB788}
103109
{9DE6373E-47EA-4B02-B1EC-4859F14A6ACD} = {9D82C3FC-EC41-4F7A-8846-D69C4CA1FA5B}
104110
{7CCE795D-D98C-41E7-834E-64A2D7B2D1DF} = {9D82C3FC-EC41-4F7A-8846-D69C4CA1FA5B}
111+
{D91FE09B-BFBB-4F96-ADAF-2D60716793F2} = {9D82C3FC-EC41-4F7A-8846-D69C4CA1FA5B}
105112
EndGlobalSection
106113
EndGlobal
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System.Web.Http;
2+
3+
namespace WebApi_Autofac
4+
{
5+
public static class WebApiConfig
6+
{
7+
public static void Register(HttpConfiguration config)
8+
{
9+
// Web API configuration and services
10+
11+
// Web API routes
12+
config.MapHttpAttributeRoutes();
13+
14+
config.Routes.MapHttpRoute(
15+
name: "DefaultApi",
16+
routeTemplate: "api/{controller}/{action}/{id}",
17+
defaults: new { id = RouteParameter.Optional }
18+
);
19+
}
20+
}
21+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Web.Http;
2+
using Microsoft.Owin.Security.Authorization.WebApi;
3+
4+
namespace WebApi_Autofac.Controllers
5+
{
6+
public class ExampleController : ApiController
7+
{
8+
[HttpGet]
9+
[ResourceAuthorize(Policy = ExampleConstants.EmployeeNumber2Policy)]
10+
public IHttpActionResult Authorized()
11+
{
12+
return Json("You are authorized now (only every third time!)");
13+
}
14+
15+
[HttpGet]
16+
[ResourceAuthorize(Roles = "admin")]
17+
public IHttpActionResult Denied()
18+
{
19+
return Json("You should never be presented this text because you will never be authorized to see it");
20+
}
21+
22+
[HttpGet]
23+
[ResourceAuthorize(Policy = "Claim_IsUser")]
24+
public IHttpActionResult Authorized2()
25+
{
26+
return Json("You are authorized!");
27+
}
28+
29+
[HttpGet]
30+
[ResourceAuthorize(Policy = "Claim_IsAdmin")]
31+
public IHttpActionResult Denied2()
32+
{
33+
return Json("You should never be presented this text because you will never be authorized to see it");
34+
}
35+
}
36+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Microsoft.Owin.Security.Authorization;
4+
5+
namespace WebApi_Autofac
6+
{
7+
public class CustomAuthorizationPolicyProvider : DefaultAuthorizationPolicyProvider
8+
{
9+
public CustomAuthorizationPolicyProvider(AuthorizationOptions options) : base(options)
10+
{
11+
}
12+
13+
public override Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
14+
{
15+
if (policyName.StartsWith("Claim_", StringComparison.InvariantCultureIgnoreCase))
16+
{
17+
var builder = new AuthorizationPolicyBuilder();
18+
var claimName = policyName.Substring(6);
19+
builder.RequireClaim(claimName, "1", "true");
20+
var policy = builder.Build();
21+
return Task.FromResult(policy);
22+
}
23+
return base.GetPolicyAsync(policyName);
24+
}
25+
}
26+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace WebApi_Autofac
2+
{
3+
public static class ExampleConstants
4+
{
5+
public const string EmployeeClaimType = "EmployeeNumber";
6+
public const string EmployeeOnlyPolicy = "EmployeeOnly";
7+
public const string EmployeeNumber2Policy = "EmployeeNumber2";
8+
}
9+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using Microsoft.Owin.Logging;
2+
using Microsoft.Owin.Security.Authorization;
3+
4+
namespace WebApi_Autofac.Models
5+
{
6+
public class EmployeeNumber2Handler : AuthorizationHandler<EmployeeNumber2Requirement>
7+
{
8+
private static int _counter = 0;
9+
10+
public EmployeeNumber2Handler(ILogger logger)
11+
{
12+
_counter++;
13+
if (_counter >= 3)
14+
_counter = 0;
15+
16+
logger.WriteInformation("current: " + _counter);
17+
}
18+
19+
protected override void Handle(AuthorizationContext context, EmployeeNumber2Requirement requirement)
20+
{
21+
foreach (var claim in context.User.Claims)
22+
{
23+
if (string.Equals(claim.Type, ExampleConstants.EmployeeClaimType))
24+
{
25+
if (claim.Value == _counter.ToString())
26+
{
27+
context.Succeed(requirement);
28+
return;
29+
}
30+
}
31+
}
32+
}
33+
}
34+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using Microsoft.Owin.Security.Authorization;
2+
3+
namespace WebApi_Autofac.Models
4+
{
5+
public class EmployeeNumber2Requirement : IAuthorizationRequirement
6+
{
7+
8+
}
9+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyTitle("WebApi_Autofac")]
9+
[assembly: AssemblyDescription("")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("")]
12+
[assembly: AssemblyProduct("WebApi_Autofac")]
13+
[assembly: AssemblyCopyright("Copyright © 2016")]
14+
[assembly: AssemblyTrademark("")]
15+
[assembly: AssemblyCulture("")]
16+
17+
// Setting ComVisible to false makes the types in this assembly not visible
18+
// to COM components. If you need to access a type in this assembly from
19+
// COM, set the ComVisible attribute to true on that type.
20+
[assembly: ComVisible(false)]
21+
22+
// The following GUID is for the ID of the typelib if this project is exposed to COM
23+
[assembly: Guid("9de6373e-47ea-4b02-b1ec-4859f14a6acd")]
24+
25+
// Version information for an assembly consists of the following four values:
26+
//
27+
// Major Version
28+
// Minor Version
29+
// Build Number
30+
// Revision
31+
//
32+
// You can specify all the values or you can default the Revision and Build Numbers
33+
// by using the '*' as shown below:
34+
[assembly: AssemblyVersion("1.0.0.0")]
35+
[assembly: AssemblyFileVersion("1.0.0.0")]

samples/WebApi Autofac/Startup.cs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Reflection;
4+
using System.Security.Claims;
5+
using System.Threading.Tasks;
6+
using System.Web.Http;
7+
using Autofac;
8+
using Autofac.Core;
9+
using Autofac.Integration.Owin;
10+
using Autofac.Integration.WebApi;
11+
using Microsoft.Owin;
12+
using Microsoft.Owin.Logging;
13+
using Microsoft.Owin.Security.Authorization;
14+
using Microsoft.Owin.Security.Authorization.Infrastructure;
15+
using Owin;
16+
using WebApi_Autofac;
17+
using WebApi_Autofac.Models;
18+
19+
[assembly: OwinStartup(typeof(Startup))]
20+
21+
namespace WebApi_Autofac
22+
{
23+
public class Startup
24+
{
25+
public delegate AuthorizationDependencies AuthorizationDependenciesFactory(AuthorizationOptions options);
26+
27+
public void Configuration(IAppBuilder app)
28+
{
29+
app.UseErrorPage();
30+
app.Use(AddEmployeeClaimBeforeAuthorizationCheck);
31+
32+
var builder = new ContainerBuilder();
33+
34+
var config = new HttpConfiguration();
35+
WebApiConfig.Register(config);
36+
37+
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
38+
builder.RegisterType<CustomAuthorizationPolicyProvider>().As<IAuthorizationPolicyProvider>().InstancePerRequest();
39+
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).Where(t => typeof(IAuthorizationHandler).IsAssignableFrom(t)).InstancePerRequest().AsImplementedInterfaces();
40+
builder.RegisterType<DefaultAuthorizationService>().As<IAuthorizationService>().InstancePerRequest();
41+
builder.RegisterType<AuthorizationDependencies>().InstancePerRequest().PropertiesAutowired();
42+
builder.RegisterInstance(new DiagnosticsLoggerFactory().Create("WebApi_Autofac_Logger"))
43+
.As<ILogger>()
44+
.SingleInstance();
45+
46+
var container = builder.Build();
47+
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
48+
49+
app.UseAutofacMiddleware(container);
50+
app.UseAutofacWebApi(config);
51+
52+
app.UseAuthorization(options =>
53+
{
54+
options.AddPolicy(ExampleConstants.EmployeeNumber2Policy, policyBuilder =>
55+
{
56+
policyBuilder.AddRequirements(new EmployeeNumber2Requirement());
57+
});
58+
}, new AuthorizationDependenciesProvider
59+
(
60+
(options, context) =>
61+
{
62+
var optionsParameter = new ResolvedParameter(
63+
(pi, ctx) => pi.ParameterType == typeof (AuthorizationOptions),
64+
(pi, ctx) => options);
65+
66+
context.GetAutofacLifetimeScope().Resolve<IAuthorizationPolicyProvider>(optionsParameter);
67+
var dependenciesFactory = context.GetAutofacLifetimeScope().Resolve<Func<AuthorizationOptions, AuthorizationDependencies>>();
68+
var dependencies = dependenciesFactory?.Invoke(options);
69+
return dependencies;
70+
}
71+
));
72+
73+
app.UseWebApi(config);
74+
}
75+
76+
private static async Task AddEmployeeClaimBeforeAuthorizationCheck(IOwinContext owinContext, Func<Task> next)
77+
{
78+
var currentIdentity = (ClaimsIdentity) owinContext.Authentication.User.Identity;
79+
if (!currentIdentity.HasClaim(x => x.Type == ExampleConstants.EmployeeClaimType))
80+
{
81+
const string currentEmployeeNumber = "2";
82+
currentIdentity.AddClaim(new Claim(ExampleConstants.EmployeeClaimType, currentEmployeeNumber));
83+
currentIdentity.AddClaim(new Claim("IsUser", "true"));
84+
currentIdentity.AddClaim(new Claim("IsAdmin", "false"));
85+
}
86+
await next();
87+
}
88+
}
89+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
3+
<!-- For more information on using web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
4+
5+
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
6+
<!--
7+
In the example below, the "SetAttributes" transform will change the value of
8+
"connectionString" to use "ReleaseSQLServer" only when the "Match" locator
9+
finds an attribute "name" that has a value of "MyDB".
10+
11+
<connectionStrings>
12+
<add name="MyDB"
13+
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
14+
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
15+
</connectionStrings>
16+
-->
17+
<system.web>
18+
<!--
19+
In the example below, the "Replace" transform will replace the entire
20+
<customErrors> section of your web.config file.
21+
Note that because there is only one customErrors section under the
22+
<system.web> node, there is no need to use the "xdt:Locator" attribute.
23+
24+
<customErrors defaultRedirect="GenericError.htm"
25+
mode="RemoteOnly" xdt:Transform="Replace">
26+
<error statusCode="500" redirect="InternalError.htm"/>
27+
</customErrors>
28+
-->
29+
</system.web>
30+
</configuration>

0 commit comments

Comments
 (0)