How to integrate custom authentication provider into IdentityServer4

前端 未结 1 1260
后悔当初
后悔当初 2020-12-30 15:34

Is it possible to somehow extend IdentityServer4 to run custom authentication logic? I have the requirement to validate credentials against a couple of existing custom ident

1条回答
  •  离开以前
    2020-12-30 15:39

    I'm assuming you have control over the clients, and the requests they make, so you can make the appropriate calls to your Identity Server.

    It is possible to use custom authentication logic, after all that is what the ResourceOwnerPassword flow is all about: the client passes information to the Connect/token endpoint and you write code to decide what that information means and decide whether this is enough to authenticate that client. You'll definitely be going off the beaten track to do what you want though, because convention says that the information the client passes is a username and a password.

    In your Startup.ConfigureServices you will need to add your own implementation of an IResourceOwnerPasswordValidator, kind of like this:

    services.AddTransient();
    

    Then in the ValidateAsync method of that class you can do whatever logic you like to decide whether to set the context.Result to a successful GrantValidationResult, or a failed one. One thing that can help you in that method, is that the ResourceOwnerPasswordValidationContext has access to the raw request. So any custom fields you add into the original call to the connect/token endpoint will be available to you. This is where you could add your custom fields (provider name, api key etc).

    Good luck!

    EDIT: The above could work, but is really abusing a standard grant/flow. Much better is the approach found by the OP to use the IExtensionGrantValidator interface to roll your own grant type and authentication logic. For example:

    Call from client to identity server:

    POST /connect/token
    grant_type=my_crap_grant&
    scope=my_desired_scope&
    rhubarb=true&
    custard=true&
    music=ska
    

    Register your extension grant with DI:

    services.AddTransient();
    

    And implement your grant validator:

    public class MyCrapGrantValidator : IExtensionGrantValidator
    {
        // your custom grant needs a name, used in the Post to /connect/token
        public string GrantType => "my_crap_grant";
    
        public async Task ValidateAsync(ExtensionGrantValidationContext context)
        {
            // Get the values for the data you expect to be used for your custom grant type
            var rhubarb = context.Request.Raw.Get("rhubarb");
            var custard = context.Request.Raw.Get("custard");
            var music = context.Request.Raw.Get("music");
    
            if (string.IsNullOrWhiteSpace(rhubarb)||string.IsNullOrWhiteSpace(custard)||string.IsNullOrWhiteSpace(music)
            {
                // this request doesn't have the data we'd expect for our grant type
                context.Result = new     GrantValidationResult(TokenRequestErrors.InvalidGrant);
                return Task.FromResult(false);
            }
    
            // Do your logic to work out, based on the data provided, whether 
            // this request is valid or not
            if (bool.Parse(rhubarb) && bool.Parse(custard) && music=="ska")
            {
                // This grant gives access to any client that simply makes a 
                // request with rhubarb and custard both true, and has music 
                // equal to ska. You should do better and involve databases and 
                // other technical things
                var sub = "ThisIsNotGoodSub";
                context.Result = new GrantValidationResult(sub,"my_crap_grant");
                Task.FromResult(0);
            }
    
            // Otherwise they're unauthorised
            context.Result = new GrantValidationResult(TokenRequestErrors.UnauthorizedClient);
            return Task.FromResult(false);
        }
    }
    

    0 讨论(0)
提交回复
热议问题