How can I get the user from my AuthorizationAttribute from within an ASPNETCORE 2.2 application? - asp.net-core

I have created a custom attribute that I would like to decorate my api controller from within my ASPNETCORE angular application. I am able to set up my authentication as required and log into the application from the login. Then I decorate my api method with my custom attribute.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = false)]
public class ManageAuditAttribute : AuthorizeAttribute, IAuthorizationFilter
{
public List<Claim> Claims { get; set; }
public ManageAuditAttribute(String feature)
{
Feature = feature;
}
public bool IsAuthorized()
{
// TODO check there is a claim for the given feature
}
private String Feature { get; }
public void OnAuthorization(AuthorizationFilterContext context)
{
var accessor = (IHttpContextAccessor)context.HttpContext.RequestServices.GetService(typeof(IHttpContextAccessor));
var name = context.HttpContext.User.FindFirst(ClaimTypes.Email); //NULL
var user = context.HttpContext.User; // NULL
var userName = Thread.CurrentPrincipal.Identity.Name; // NULL
}
}
Before saying that claims are not used this way I would add that I need to fit this into a legacy system that has a list of allowed features. I am adding those features to the user as claims and checking the claim exists for each user. The value for the actual claim is the name of the application that the user needs the claim for.
I could easily add these as a custom list to my custom identity user which might be more fitting however, I still need to access my user.
I can get the user but the name is always null and my claims list is empty as well. It is as if I am not logged in at all. Even after logging in.

For retrieving name, you should pass ClaimTypes.Name instead of ClaimTypes.Email like
var user = context.HttpContext.User.FindFirst(ClaimTypes.Name);
Or, you could retrieve by HttpContext.User.Identity.Name like
var userName = context.HttpContext.User.Identity.Name;

I have solved you problem by adding:
app.UseAuthentication();
in Startup.cs.

Related

Using Client Credetials as the part of Usermanager<User>

Currently i am using Password Flow with my SPA application.
Now i had to integrate Client Credentials flow with my current implementation.
var descriptor = new OpenIddictApplicationDescriptor
{
ClientId = "console",
ClientSecret = "388D45FA-B36B-4988-BA59-B187D329C207",
DisplayName = "My client application",
Permissions =
{
OpenIddictConstants.Permissions.Endpoints.Token,
OpenIddictConstants.Permissions.GrantTypes.ClientCredentials
}
I have successfully implemented the both integration on my system. When sending the request using the client_id the app is authorized and authenticated as expected.
But as i notice that when using the Password flow i as using ApplicationUser as a part of Asp.net identity from dbo.User table.
But client credentials comes from different namespace that is not linked up with the Application User.
How can i setup the client_id as the part of dbo.User. How to link the the Client Credetials with Usermanager<User>?
Why i want this implementation is because during the crud operation i have the column name CreatedBy. which is refrenced to table dbo.User and i wanted to fill up the Id from dbo.User. But in the client credetials flow do not have the User.
Getting UserId
public interface IUserResolverService
{
HttpContext HttpContext { get; }
Task<Guid> GetUserId();
}
public class UserResolverService : IUserResolverService
{
IHostingEnvironment _hostingEnv;
private readonly IHttpContextAccessor accessor;
private readonly UserManager<User> _user;
public UserResolverService(IHttpContextAccessor accessor, UserManager<User> user, IHostingEnvironment hostingEnv)
{
this._user = user;
this.accessor = accessor;
this._hostingEnv = hostingEnv;
}
public HttpContext HttpContext
{
get { return accessor.HttpContext; }
}
public async Task<Guid> GetUserId()
{
var user = await _user.GetUserAsync(accessor.HttpContext.User);
return user?.Id ?? Guid.Empty;
}
}
Can you suggest me a way for this scenario?
How can i setup the client_id as the part of dbo.User. How to link the the Client Credetials with Usermanager?
It's not possible and it doesn't make any sense, actually. The client credentials is the only OAuth 2.0 core flow that doesn't involve any user as it's been designed for service-to-service scenarios, where the client application doesn't act on behalf of a user, but directly under its own identity.
To work around your issue, you may want to either make CreatedBy nullable or use one of the claim representing the application you use in AuthorizationController, like the client identifier or the client name.

authorize logged in user against url

My goal is to authorize users only if the current logged on user's customerId matches the customerId on the url/controller.
I'm using ASP.NET Core 2.0 with entity framework. I have extended ApplicationUser with a CustomerId int that has a FK to a CustomerIdentity table.
I am able to retrieve the customerId from the logged in user, using this method here: http://rion.io/2016/01/04/accessing-identity-info-using-dependency-injection-in-net-5/
I have made a routing:
routes.MapRoute(
name: "customers",
template: "{customerId?}/{controller=Home}/{action=Index}/{id?}");
And then in my controllers I have a customerId parameter.
Global admins have the rights to use any customerId they like, but for everyone else they can only use their customerId belonging to their logged in user.
I was thinking of using this approach to check if customerId from url, e.g. /23/Computers/Approve matches currentCustomerId
But I'm not sure how to adapt it to a policy and claim that asp.net core uses.
What I have sofar:
public class CustomerRequirement : IAuthorizationRequirement
{
public bool IsMatchingLoggedInUser { get; private set; }
public CustomerRequirement(bool isMatchingLoggedInUser)
{
IsMatchingLoggedInUser = IsMatchingLoggedInUser;
}
}
Not sure how to make this one:
public class CustomerRequirementHandler : AuthorizationHandler<CustomerRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomerRequirement requirement)
{
//GetDate.CurrentCustomerId is a static int property set after user has logged in
if (GetData.CurrentCustomerId == /*Get httpContext customerId ??? "")*/ 42)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
Not sure if I'm totally off here or it can be done differently? I am open for suggestions.
Update (what I ended up with)
public class ValidateCustomerAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (GetData.CurrentCustomerId != (int)context.ActionArguments["customerId"])
{
context.Result = new UnauthorizedResult();
}
}
}
Then on my controllers I decorated it with this attribute. I still need to exclude admins in this, but that will come later. (and some more errorhandling :))
I'm not familiar with how ASP.NET Core does this (is AuthorizationHandler similar to an action filter?), but this seems like something you can handle using roles.
I have a custom Auth action filter where I put custom validation logic like this. In the controller, you could check the roles of the logged in user. If they don't have role "Admin" and their customer ID does not match the customer ID in the URL, return a 403. Otherwise, continue as normal.
If getting the value of the customer ID is a problem for you and you don't have access to the action parameters, then you can use the current request's Uri, split the path apart and pull it out that way. But that's a fragile implementation.

Recommended best practice for role claims as permissions

The app I am working on is a SPA and we are using JWT Bearer authentication and OpenIdConnect/OAuth2 when communicating with our backend API which uses .NETCore and ASP.NET Identity. Our API endpoints are secured using Custom Policy based authentication as shown here:
Custom Policy Based Authentication
We decided to use the out of the box AspNetRoleClaims table to store claims for our users as permissions. Each user is assigned 1 primary role although the potential is there to have multiple roles. Each role will have many claims - which are stored in the AspNetRoleClaims table.
Role claims would look like this:
ClaimType: Permission
ClaimValue(s):
MyModule1.Create
MyModule1.Read
MyModule1.Edit
MyModule1.Delete
MyModule1.SomeOtherPermission
MyModule2.Read
MyModule3.Read
MyModule3.Edit
etc.
The more permissions or role claims that a user has, the larger the access_token will be, thereby increasing the HTTP header size. Also the ASP.NET Identity Authorization cookie - as there are more and more role claims it gets chunked out into multiple cookies.
I have experimented with adding in a lot of role claims and eventually the request fails because the header gets too big.
I am looking for some advice on what is considered "best practice" when it comes to bearer authentication with role claims. Microsoft gives you AspNetRoleClaims out of the box that work for my scenario and from what I understand the advantage of storing these role claims in the access_token is that we don't have to hit the database on each API endpoint that is secured with the custom policy.
The way I see it, I can try to make the claim values smaller, and in the case of where a user has multiple roles that may share common role claims that are duplicated, I can try to intercept when these get written into the cookie and remove the duplicates.
However, since the app is still in development, I can foresee more and more roles claims being added and there is always the possibility that the HTTP header will become too large with the cookies and the access_token. Not sure if this is the best approach.
The only alternative I see is to hit the database each time we hit our protected API. I could inject a DbContext in each custom claim policy requirement handler and talk to the AspNetRoleClaims table on each request.
I haven't seen too many examples out there of how people accomplish a more finely grained permissions scheme with ASP.NET Identity and .NET Core API. This must be a fairly common requirement I would think...
Anyways, just looking for some feedback and advice on recommended best practice for a scenario like this.
****UPDATE - See answer below ****
I never did find a recommended "best practice" on how to accomplish this but thanks to some helpful blog posts I was able to architect a nice solution for the project I was working on. I decided to exclude the identity claims from the id token and the Identity cookie and do the work of checking the users permissions (role claims) server side with each request.
I ended up using the architecture are described above, using the built in AspNetRoleClaims table and populating it with permissions for a given role.
For example:
ClaimType: Permission
ClaimValue(s):
MyModule1.Create
MyModule1.Read
MyModule1.Edit
MyModule1.Delete
I use Custom policy based authentication as described in the Microsoft article in the link above.
Then I lock down each of my API endpoints with the Role based policy.
I also have an enum class that has all the permissions stored as enums. This enum just lets me refer to the permission in code without having to use magic strings.
public enum Permission
{
[Description("MyModule1.Create")]
MyModule1Create,
[Description("MyModule1.Read")]
MyModule1Read,
[Description("MyModule1.Update")]
MyModule1Update,
[Description("MyModule1.Delete")]
MyModule1Delete
}
I register the permissions in Startup.cs like so:
services.AddAuthorization(options =>
{
options.AddPolicy("MyModule1Create",
p => p.Requirements.Add(new PermissionRequirement(Permission.MyModule1Create)));
options.AddPolicy("MyModule1Read",
p => p.Requirements.Add(new PermissionRequirement(Permission.MyModule1Read)));
options.AddPolicy("MyModule1Update",
p => p.Requirements.Add(new PermissionRequirement(Permission.MyModule1Update)));
options.AddPolicy("MyModule1Delete",
p => p.Requirements.Add(new PermissionRequirement(Permission.MyModule1Delete)));
}
So there is a matching Permission and a PermissionRequirement like so:
public class PermissionRequirement : IAuthorizationRequirement
{
public PermissionRequirement(Permission permission)
{
Permission = permission;
}
public Permission Permission { get; set; }
}
public class PermissionRequirementHandler : AuthorizationHandler<PermissionRequirement>,
IAuthorizationRequirement
{
private readonly UserManager<User> _userManager;
private readonly IPermissionsBuilder _permissionsBuilder;
public PermissionRequirementHandler(UserManager<User> userManager,
IPermissionsBuilder permissionsBuilder)
{
_userManager = userManager;
_permissionsBuilder = permissionsBuilder;
}
protected override async Task HandleRequirementAsync(
AuthorizationHandlerContext context,
PermissionRequirement requirement)
{
if (context.User == null)
{
return;
}
var user = await _userManager.GetUserAsync(context.User);
if (user == null)
{
return;
}
var roleClaims = await _permissionsBuilder.BuildRoleClaims(user);
if (roleClaims.FirstOrDefault(c => c.Value == requirement.Permission.GetEnumDescription()) != null)
{
context.Succeed(requirement);
}
}
}
The extension method on the permission GetEnumDescription just takes the enum that I have in the code for each permission and translates it to the same string name as it is stored in the database.
public static string GetEnumDescription(this Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(
typeof(DescriptionAttribute),
false);
if (attributes != null &&
attributes.Length > 0)
return attributes[0].Description;
else
return value.ToString();
}
My PermissionHandler has a PermissionsBuilder object. This is a class I wrote that will hit the database and check if the logged in user has a particular role claim.
public class PermissionsBuilder : IPermissionsBuilder
{
private readonly RoleManager<Role> _roleManager;
public PermissionsBuilder(UserManager<User> userManager, RoleManager<Role> roleManager)
{
UserManager = userManager;
_roleManager = roleManager;
}
public UserManager<User> UserManager { get; }
public async Task<List<Claim>> BuildRoleClaims(User user)
{
var roleClaims = new List<Claim>();
if (UserManager.SupportsUserRole)
{
var roles = await UserManager.GetRolesAsync(user);
foreach (var roleName in roles)
{
if (_roleManager.SupportsRoleClaims)
{
var role = await _roleManager.FindByNameAsync(roleName);
if (role != null)
{
var rc = await _roleManager.GetClaimsAsync(role);
roleClaims.AddRange(rc.ToList());
}
}
roleClaims = roleClaims.Distinct(new ClaimsComparer()).ToList();
}
}
return roleClaims;
}
}
I build up a list of distinct role claims for a user - I use a ClaimsComparer class to help do this.
public class ClaimsComparer : IEqualityComparer<Claim>
{
public bool Equals(Claim x, Claim y)
{
return x.Value == y.Value;
}
public int GetHashCode(Claim claim)
{
var claimValue = claim.Value?.GetHashCode() ?? 0;
return claimValue;
}
}
The controllers are locked down with the role based custom policy:
[HttpGet("{id}")]
[Authorize(Policy = "MyModule1Read", AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public IActionResult Get(int id){
Now here is the important part - you need to override the UserClaimsPrincipalFactory in order to prevent the role claims from being populated into the Identity cookie. This solves the problem of the cookie and the headers being too big. Thanks to Ben Foster for his helpful posts (see links below)
Here is my custom AppClaimsPrincipalFactory:
public class AppClaimsPrincipalFactory : UserClaimsPrincipalFactory<User, Role>
{
public AppClaimsPrincipalFactory(UserManager<User> userManager, RoleManager<Role> roleManager, IOptions<IdentityOptions> optionsAccessor)
: base(userManager, roleManager, optionsAccessor)
{
}
public override async Task<ClaimsPrincipal> CreateAsync(User user)
{
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
var userId = await UserManager.GetUserIdAsync(user);
var userName = await UserManager.GetUserNameAsync(user);
var id = new ClaimsIdentity("Identity.Application",
Options.ClaimsIdentity.UserNameClaimType,
Options.ClaimsIdentity.RoleClaimType);
id.AddClaim(new Claim(Options.ClaimsIdentity.UserIdClaimType, userId));
id.AddClaim(new Claim(Options.ClaimsIdentity.UserNameClaimType, userName));
if (UserManager.SupportsUserSecurityStamp)
{
id.AddClaim(new Claim(Options.ClaimsIdentity.SecurityStampClaimType,
await UserManager.GetSecurityStampAsync(user)));
}
// code removed that adds the role claims
if (UserManager.SupportsUserClaim)
{
id.AddClaims(await UserManager.GetClaimsAsync(user));
}
return new ClaimsPrincipal(id);
}
}
Register this class in Startup.cs
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// override UserClaimsPrincipalFactory (to remove role claims from cookie )
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, AppClaimsPrincipalFactory>();
Here are the links to Ben Foster's helpful blog posts:
AspNet Identity Role Claims
Customizing claims transformation in AspNet Core Identity
This solution has worked well for the project I was working on - hope it helps someone else out.
I haven't seen too many examples out there of how people accomplish a more finely grained permissions scheme with ASP.NET Identity and .NET Core API. This must be a fairly common requirement I would think...
Your current design is RBAC (Role Based Access Control). Since you are experiencing a "role explosion", you need ReBAC (Relationship Based Access Control), which allows for fine-grained permissions. See my other answer here for more details on current offerings.

Setting user-specific culture in a ServiceStack + MVC web application

I need to set user-specific culture for every web request sent to my web application written using ServiceStack 3 and MVC 4.
Each user's culture is stored in their profile in the database, which I retrieve into my own implementation of IAuthSession using a custom auth provider derived from CredentialsAuthProvider. So I don't care about the browser's AcceptLanguage header and instead want to set the current thread's culture to the Culture property of the auth session right after ServiceStack resolves it from the cache. This has to happen for both ServiceStack services and MVC controllers (derived from ServiceStackController).
What's the best way to accomplish the above?
UPDATE 1
I have found a way to do this, although I'm not convinced that this is the optimal solution.
In my base service class from which all services derive I overrode the SessionAs<> property as follows:
protected override TUserSession SessionAs<TUserSession>()
{
var genericUserSession = base.SessionAs<TUserSession>();
var userAuthSession = genericUserSession as UserAuthSession;
if (userAuthSession != null && !String.IsNullOrWhiteSpace(userAuthSession.LanguageCode))
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(userAuthSession.LanguageCode);
return genericUserSession;
}
where UserAuthSession is my custom implementation of ServiceStack's IAuthSession. Its LanguageCode property is set at login time to the user's chosen ISO culture code stored in the user's profile in the database.
Similarly, in my base controller class from which all my controllers derive I overrode the AuthSession property like so:
public override IAuthSession AuthSession
{
get
{
var userAuthSession = base.AuthSession as UserAuthSession;
if (userAuthSession != null && !String.IsNullOrWhiteSpace(userAuthSession.LanguageCode))
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(userAuthSession.LanguageCode);
return userAuthSession;
}
}
This seems to work fine because these two properties are used consistently whenever a service is invoked or a controller action is executed, so the current thread's culture gets set before any downstream logic is executed.
If anyone can think of a better approach please let me know.
UPDATE 2
Based on Scott's suggestion I created a custom AuthenticateAndSetCultureAttribute:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class AuthenticateAndSetCultureAttribute : AuthenticateAttribute
{
public AuthenticateAndSetCultureAttribute() : base() { }
public AuthenticateAndSetCultureAttribute(ApplyTo applyTo) : base(applyTo) { }
public AuthenticateAndSetCultureAttribute(string provider) : base(provider) { }
public AuthenticateAndSetCultureAttribute(ApplyTo applyTo, string provider) : base(applyTo, provider) { }
public override void Execute(IHttpRequest req, IHttpResponse res, object requestDto)
{
base.Execute(req, res, requestDto);
var session = req.GetSession() as UserAuthSession;
if (session != null && session.IsAuthenticated && !String.IsNullOrWhiteSpace(session.LanguageCode))
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(session.LanguageCode);
}
}
Because I only change the culture when the user is authenticated, it makes sense (in my mind anyways) to do it in the same place where we check for authentication.
I then decorated all my SS services and MVC controllers with this attribute instead of the original [Authenticate].
Now when a SS service is called the attribute's Execute method is executed, and the culture gets correctly set. However, Execute never gets executed when an MVC controller action is invoked, which is really puzzling because how then does MVC+SS know to redirect unauthenticated requests to the login page.
Any thoughts, anybody?
I would do this using a RequestFilter rather than overriding the SessionAs<T>. In your AppHost Configure method:
public override void Configure(Container container)
{
RequestFilters.Add((httpReq, httpResp, requestDto) => {
var session = httpReq.GetSession() as UserAuthSession;
if(session == null || !session.IsAuthenticated || String.IsNullOrWhiteSpace(session.LanguageCode))
return;
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(session.LanguageCode);
});
}
I ended up creating a custom MVC action filter that sets the request thread's culture based on the authenticated user's settings:
public class SetUserCultureAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
var baseController = filterContext.Controller as BaseController;
if (baseController == null) return;
var userAuthSession = baseController.UserAuthSession;
if (userAuthSession != null && userAuthSession.IsAuthenticated && !String.IsNullOrWhiteSpace(userAuthSession.LanguageCode))
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(userAuthSession.LanguageCode);
}
}
Then I decorated my BaseController class with this attribute, and secured my controllers/actions with ServiceStack's regular Authorize attribute.
The previously created AuthenticateAndSetCultureAttribute that I originally intended to work for both controllers and services now is used for SS services only.
The culture is getting set correctly on both the MVC and the SS side, so I'm happy!

Adding RequestFilter data to Context (Request Scope), Retrieve in Service

I implemented Basic Auth for my services. Since ServiceStack's AuthFeature is strongly coupled with the session concept, I implemented a custom RequestFilter that performs stateless basic auth (credentials go in, on every request). Our auth strategy internally contemplates roles and permissions.
Besides authentication, we need to enforce authorization (e.g., user is manipulating a product that he owns). We are using FluentValidation, for all service validations.
Authorization validations include cross checking auth data with request parameters. Question is, where should I place the auth data produced in the BasicAuthRequestFilter? Should I key value pair it in cache, associating, for instance, RequestContext (or any other object that uniquely identifies the request scope) with an Authentication object?
I could just plug the AuthData in the Request Dto, which is available directly at the RequestFilter, however this would mess up our service contract design. We define dtos in a separate DLL, where only service input/output details are defined.
Any suggestions?
Thanks in advance.
I too use my own custom authentication mechanism and make custom role information available to my service. I do this by authenticating the request in a custom ServiceRunner which can then pass the information directly to my custom Service base. This ultimately means accessing information about the users permissions is exceptionally easy.
Create a custom ServiceRunner:
public class ServiceRunner<T> : ServiceStack.ServiceHost.ServiceRunner<T>
{
public ServiceRunner(IAppHost appHost, ActionContext actionContext) : base(appHost, actionContext)
{
}
public override object Execute(IRequestContext requestContext, object instance, T request)
{
// Check if the instance is of type AuthenticatedBase
var authenticatedBase = instance as AuthenticatedBase;
// If the request is not using the AuthenticatedBase, then allow it to run, as normal.
if(authenticatedBase == null)
return base.Execute(requestContext, instance, request);
/*
* Authentication required. Do you authorization check here.
* i.e.
* var authorization = requestContext.GetHeader("Authorization");
* bool authorised = ... some condition;
*/
/* You have access to your service base so if you injected the Db connection
* in you app config using IoC, then you can access the Db here.
* i.e.
* authenticatedBase.Db
*/
/*
* Not authorized?
* throw new UnauthorizedException();
*/
/*
* If authorized:
* Then simple set the details about their permissions
*/
authenticatedBase.AuthData = new AuthData { Id = 123, Roles = [], Username = "" };
// Pass back the authenticated base
return base.Execute(requestContext, authenticatedBase, request);
}
}
Configure you application to use it by adding this to your AppHost:
public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(ActionContext actionContext)
{
return new ServiceRunner<TRequest>(this, actionContext);
}
Create a custom class to hold your auth data i.e. the user session information, such as:
public class AuthData
{
public int Id { get; set; }
public string Username { get; set; }
public int[] Roles { get; set; }
...
}
Then create a custom service base
public class AuthenticatedBase : Service
{
public AuthData AuthData { get; set; }
}
To then use the AuthData in the service is simply a case of extending AuthenticatedBase.
public class CustomerHandler : AuthenticatedBase
{
public object Get(ListCustomers request)
{
// You can access the AuthData now in the handler
var roles = AuthData.Role; // Check they have the role required to list customers
...
}
}
You are probably wondering why go to all the trouble of using the ServiceRunner over a RequestFilter but the main advantage is it gives direct access to the instance of the Service base, which isn't available to a RequestFilter.
The RequestFilters are run before the Service base is instantiated, so you can't populate it from there. See order of operations for more information.
By having access to the ServiceBase we can populate values (in this case AuthData) and we have access to our injected dependancies such as the database connection.
I hope you find this useful. You should be able to copy most of your existing RequestFilter into the service runner. If you need any further help with this just let me know.
Update to support Attributes:
Since you are unable to avoid using the attribute method to handle your authentication needs you can still use this method:
Continue doing your authentication and access filtering the way you were before.
In your existing authentication mechanism use req.Items.Add to set the AuthData i.e. Where req is your request object
req.Items.Add("AuthData", new AuthData { Username = "", Roles = [] ... });
Then access your AuthData item in your service base:
public class AuthenticatedBase : Service
{
public AuthData AuthData
{
get { return base.Request.Items["AuthData"] as AuthData; }
}
}