1
\$\begingroup\$

I'm doing an AuthorizationService. I'm not sure how to do the usage interface of this service, so that it's practical and handy. It doesn't necessarily has to be an interface, for example in my version it's a singleton class.

At the moment, the usage of this service is like this:

var authorizationRequestForCertainActio = GetRequestFromSomewhere();
var customClaimProvider = new CustomClaimsProvider();
var customClaimBasedFactFunction = new CustomClaimBasedFactFunction();

//is it ok to require registrations and Initialize() go first
AuthorizationService.Instance.RegisterClaimsProvider<CustomClaimsProvider>("provider_with_id_1");
AuthorizationService.Instance.RegisterClaimBaisedFactFunction<CustomClaimBasedFactFunction>("fact_function_with_id_1");
AuthorizationService.Instance.Initialize();

//and only after that let exceptionless CheckAccess() 
AuthorizationService.Instance.CheckAccess(authorizationRequestForCertainAction);

Defenately, some smell here. But, i kinda think that it would be easy to use it when it is a singleton.


It happens that i already have an idea how to design this complex authorization service inside. This question is only about the top part of the iceberg. But just in case, i'll say a couple of words about how i want this service to work:

  • The purpose of the service is to have a method: bool CheckAccess(authorizationRequest)
  • The service has to be initialized first. I.e. some authorization rules should be taken from an XML or JSON file via an IAuthorizationModelProvider
  • However, before the Initialize()ation, some custom elements should be registered in the service in order for the AuthorizationModel to be read from a file. These elements are IClaimsProviders, which designate claims from AuthorizationRequest, and IClaimBasedFactFunctions, which perform logical operation upon the IClaimsProviders.

Here is the code of the service itself:

public sealed class AuthorizationService //singleton
{
    //--------------------------------------------------

    public ClaimsAuthorizationManager AuthorizationManager { get; private set; } //Microsoft class from Windows Identity Foundation

    public readonly IContainer Container = new Container(); //DryIoc container

    //--------- one may register custom implementations before calling Initialize():

    public void RegisterClaimsProvider<TClaimsProvider>(string id) where TClaimsProvider: IClaimsProvider
    {
        Container.Register<TClaimsProvider>(serviceKey: id);
    }

    public void RegisterClaimBaisedFactFunction<TClaimBasedFactFunction>(string id) where TClaimBasedFactFunction: IClaimBasedFactFunction
    {
        Container.Register<TClaimBasedFactFunction>(serviceKey: id);
    }

    //if this provider is not registered outside then default implementation should be registered inside InitializeContainer() 
    public void RegisterAuthorizationModelProvider<TAuthorizationModelProvider>(string id) where TAuthorizationModelProvider : IAuthorizationModelProvider
    {
        Container.Register<TAuthorizationModelProvider>(serviceKey: id);
    }

    //-------------------------------------------------------

    public void Initialize()
    {
        InitializeContainer();

        var modelProvider = Container.Resolve<IAuthorizationModelProvider>();
        var model = modelProvider.GetModel();
        AuthorizationManager = new AuthorizationManager(model); //custom realization of Microsoft's ClaimsAuthorizationManager

        FederatedAuthentication.ServiceConfiguration.ClaimsAuthorizationManager = AuthorizationManager; //Microsoft's stuff
    }

    public bool CheckAccess(AuthorizationContext request) //AuthorizationContext is a Microsoft class from Windows Identity Foundation
    {
        if (AuthorizationManager == null)
            throw new Exception("Service not initialized. Initialize() method should be called first");

        return AuthorizationManager.CheckAccess(request);
    }

    //--------------------------------------------------------

    private void InitializeContainer()
    {
        throw new NotImplementedException();
    }

    //------------- singleton ----------------------------------

    private static readonly Lazy<AuthorizationService> lazy =
        new Lazy<AuthorizationService>(() => new AuthorizationService());

    public static AuthorizationService Instance { get { return lazy.Value; } }

    private AuthorizationService()
    {

    }
}
\$\endgroup\$
  • \$\begingroup\$ How many TClaimsProviders and TClaimBasedFactFunctions are there? If more than one combination is possible, then why is the AuthorizationService a singleton? \$\endgroup\$ – 200_success Mar 1 '16 at 22:21
  • \$\begingroup\$ Thanks! More than one. Possibly, many. Sorry, not sure what you mean. I thought that singleton is useful because the service should be used all over the place. For every action of a system there should be a call to this function. \$\endgroup\$ – Andrey K. Mar 1 '16 at 23:29
  • \$\begingroup\$ If there are ClaimsProvider×FactFunction combinations, which of those configurations is your singleton supposed to represent? \$\endgroup\$ – 200_success Mar 1 '16 at 23:33
  • \$\begingroup\$ The inner stuff will be complicated. Those facts and providers will be inside the container, which is used by the IAuthorizationModelProvider (via ServiceLocator). But it's not what i wanted to ask. The main thing is to figure out how to initialize() a singleton, but also to somehow inject other elements. Sorry, the question is confusing. I should think of an easier abstraction of this question. \$\endgroup\$ – Andrey K. Mar 1 '16 at 23:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.