ASP. NET core external authentication Multi-site mode implementation

Source: Internet
Author: User
Tags oauth


PS: Before because need to expand and QQ authentication, make the website is can use QQ and direct login. GitHub portal. Then a small partner asked if the configuration information (AppID, Appsecret) can be changed as needed instead of being written in Configureservices.



First on official documents: docs.microsoft.com/zh-cn/aspnet/core/security/authentication/social/?view=aspnetcore-2.1



The official has achieved the microsft,facebook,twitter,google and so on these several website authentication. The code can be certified to the authorization library to see Github.com/aspnet/security found.



Domestic QQ and is actually based on OAuth to achieve, so their integration is relatively easy.



Under normal circumstances, the configuration of this external authentication is configured in the Configureservices, and the use of configuration or the use of confidential documents in the form of saving appid and other information.



Back to the text, multi-site mode, is a site is divided into multiple sub-sites, and different sub-sites can be configured with different AppID. The default configuration mode for ASP. NET core is not suitable for this scenario.



First on code: Github.com/jxnkwlp/aspnetcore.authenticationqq-webchat/tree/muti-site


Official Code Analysis:


1,remoteauthenticationhandler Remote Authentication handler. Located under Microsoft.aspnetcore.authentication. Source Code (Github.com/aspnet/security/blob/master/src/microsoft.aspnetcore.authentication/remoteauthenticationhandler.cs)



This is a generic class and requires a toptions, and this toptions must be a class that inherits Remoteauthenticationoptions.






2,oauthhandler implements the OAuth authentication handler, which inherits the Remoteauthenticationhandler. A oauthoptions must also be implemented.



Under normal circumstances, the implementation of QQ, GitHub, Google, Facebook and other logins are based on this to achieve. Oauthhandler has implemented the standard OAuth authentication.



Source: Github.com/aspnet/security/blob/master/src/microsoft.aspnetcore.authentication.oauth/oauthhandler.cs



In Configureservices, the use of Addfacebook, and so on, is to add the Handler to the processing pipeline, which is to implement OAuth, and then pass the corresponding Options to configure the Handler.






3, back to Account/externallogin, in the request to submit an external login, authenticationproperties properties = _  Signinmanager.configureexternalauthenticationproperties (provider, RedirectURL); The purpose of this line of code is to configure the current external login return URL and authentication related properties.  Return Challenge (properties, provider); The result is transferred to the relevant related handler. The result returned here is used for the above Oauthhandler as a processing parameter. From here on, it has entered the oauthhandler of the processing area.






4. View the Oauthhandler code.  Task Handlechallengeasync (authenticationproperties properties);   This function acts as the authentication parameter that is passed in the previous step. Default implementation code:


protected override async Task HandleChallengeAsync(AuthenticationProperties properties) 
{

    if (string.IsNullOrEmpty(properties.RedirectUri)) 
    { 
        properties.RedirectUri = CurrentUri; 
    }

    // OAuth2 10.12 CSRF

    GenerateCorrelationId(properties);

    var authorizationEndpoint = BuildChallengeUrl(properties, BuildRedirectUri(Options.CallbackPath));

    var redirectContext = new RedirectContext<OAuthOptions>(

        Context, Scheme, Options,

        properties, authorizationEndpoint);

    await Events.RedirectToAuthorizationEndpoint(redirectContext); 
} 
protected virtual string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri)
{
 var scopeParameter = properties.GetParameter<ICollection<string>>(OAuthChallengeProperties.ScopeKey);
    var scope = scopeParameter != null ? FormatScope(scopeParameter) : FormatScope();

    var state = Options.StateDataFormat.Protect(properties);
    var parameters = new Dictionary<string, string>
    {
        { "client_id", Options.ClientId },
        { "scope", scope },
        { "response_type", "code" },
        { "redirect_uri", redirectUri },
        { "state", state },
    };

    return QueryHelpers.AddQueryString(Options.AuthorizationEndpoint, parameters);
} 

In this case, a request URL is constructed, which is the URL authorized by the target site, such as a page with two-dimensional code in the middle of the black background. This method of building the request URL can be overridden.



5, in the previous step, in the need to authorize the site, after the authorization is completed, will jump to their own website and with the authorization related data. The entrance is task

Transformation method:


In the above analysis, the official implementation is to configure the parameter Toptions in Configureservices, and then get the parameter in Handler. Our goal is to change the parameters, such as client_id, as needed in the request.



1, define an interface Iclientstore and an entity Clientstoremodel.



Public interface IClientStore
{
     /// <summary>
     /// Search by <paramref name="provider"/> and <paramref name="subjectId"/> <seealso cref="ClientStoreModel"/>
     /// </summary>
     ClientStoreModel FindBySubjectId(string provider, string subjectId);
}



/// <summary>
/// indicates a Client message
/// </summary>
Public class ClientStoreModel
{
     Public string Provider { get; set; }

     Public string SubjectId { get; set; }

     /// <summary>
     /// Gets or sets the provider-assigned client id.
     /// </summary>
     Public string ClientId { get; set; }

     /// <summary>
     /// Gets or sets the provider-assigned client secret.
     /// </summary>
     Public string ClientSecret { get; set; }

}



Iclientstore to find the configuration information for the client



2, in Account/externallogin, a new parameter, Subjectid, indicates which request (Subjectid) is in one of the current certifications (Provider).



The Subjectid is also saved in the authorization configuration parameters that are returned.









3, define a Multioauthhandler, integrate Remoteauthenticationhandler, do not inherit Oauthhandler because a new Options is needed here. (See code warehouse for full code) definition: Class multioauthhandler<tmultioauthoptions>:remoteauthenticationhandler< Tmultioauthoptions>wheretmultioauthoptions:multioauthoptions,new ()



Add the parameter Iclientstore in the constructor.



4, in the default implementation, from the external licensing site to jump back to their site, the default path is/signin-{provider}, such as/signin-microsoft. To differentiate the requested Subjectid, the default path is changed to/signin-{provider}/subject/{subjectid}.



5, modify Handleremoteauthenticateasync, add 2 lines of code at the beginning to get Subjectid.



var callbackpath = Options.CallbackPath.Add ("/subject"). Value; var subjectid = Request.Path.Value.Remove (01);





6, modify the Exchangecodeasync method


protected virtual async Task<OAuthTokenResponse> ExchangeCodeAsync(string subjectId, string code, string redirectUri)
{
    var clientStore = GetClientStore(subjectId);

    var tokenRequestParameters = new Dictionary<string, string>()
    {
        { "client_id", clientStore.ClientId },
        { "client_secret", clientStore.ClientSecret },

        { "redirect_uri", redirectUri },
        { "code", code },
        { "grant_type", "authorization_code" },
    };

    var requestContent = new FormUrlEncodedContent(tokenRequestParameters);

    var requestMessage = new HttpRequestMessage(HttpMethod.Post, Options.TokenEndpoint);
    requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    requestMessage.Content = requestContent;
    var response = await Backchannel.SendAsync(requestMessage, Context.RequestAborted);
    if (response.IsSuccessStatusCode)
    {
        var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
        return OAuthTokenResponse.Success(payload);
    }
    else
    {
        var error = "OAuth token endpoint failure: " + await Display(response);
        return OAuthTokenResponse.Failed(new Exception(error));
    }
} 



7, there are some minor changes, it is not listed here. Here Multioauthhandler the related to adjust well.



I left this alone, Microsoft.AspNetCore.Authentication.MultiOAuth.






8, use. Implement the Iclientstore interface, and then add the following code to the Configureservices:



Services. Addauthentication ()    . Addmultioauthstore<mylientstore> ()     





9, currently on GitHub on the demo only to do the implementation.






PS: If there is any mistake, please correct me.






Source Address: Blog.wuliping.cn/post/aspnet-core-security-authentication-social-multi-config





Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.