如何调用受密钥斗篷保护的api?

时间:2019-02-21 13:26:43

标签: keycloak

我有dotnet核心的angular应用程序,其中的api使用keycloak保护,并且还有前端的前端,该前端由登录页面(基本上是keycloak登录页面)组成。我有另一个dotnet控制台应用程序,用于调用受keycloak保护的api。我的应用程序和keycloak服务器在aws实例上运行,而控制台应用程序在我的本地系统上。因此,如何从控制台应用程序调用这些api。 下面我提到了我的keycloak配置和startup.cs代码。

{
"Type": "Development System : http localhost --> This is for development\\debugging only",
"Authentication": {
  "OIDC": {
    "DefaultSchema": "ZMOD.KeyCloak",
    "Cookies": "ZMOD.Cookies",
    "AuthorizationEndpoint": "https://accounts.zmod.org/auth/realms/master",
    "TokenEndpoint": "https://accounts.zmod.org/auth/realms/master/protocol/openid-connect/token",
    "UserInformationEndpoint": "https://accounts.zmod.org/auth/realms/master/protocol/openid-connect/userinfo",
    "CallBack": "/signin-oidc",
    "SignOutRedirectURL": "http://localhost:5000",
    "ClientId": "myclient",
    "ClientSecret": "<client_secret>",
    "ResponseType": "code id_token",
    "IsSecuredHTTP": false
  }
}
}

Startup.cs

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json.Linq;
using ZMM.App.PyServicesClient;
using ZMM.App.ZSServiceClient;
using ZMM.Authorizations.Claims;
using ZMM.Helpers.ZMMDirectory;
//using Swashbuckle.AspNetCore.Swagger;
using System.IO;
using Microsoft.AspNetCore.SpaServices.AngularCli;
using Microsoft.OpenApi.Models;
namespace ZMM.App
{
public class StartupDevelopment
{

    private readonly ILogger Logger;
    public IConfiguration Configuration { get; }
    public IHostingEnvironment Environment { get; }

    private string ContentDir = string.Empty;

    private const string XForwardedPathBase = "X-Forwarded-PathBase";
    private const string XForwardedProto = "X-Forwarded-Proto";

    public StartupDevelopment(IConfiguration configuration, 
    IHostingEnvironment environment,ILogger<StartupDevelopment> logger)
    {
        Configuration = configuration;
        Environment = environment;
        Logger = logger;
        Logger.LogInformation("Initializing " + Configuration["Type"]);
        InitContentDir(ref ContentDir);
    }        


    // This method gets called by the runtime. Use this method to add 
    services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        #region MVC behaviour to specific .net version 2.2

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);     
        #endregion            
        #region Development profile works with "npm" and "ng server" with 
    dotnet 2.2 inbuilt configuration
        services.AddSpaStaticFiles(configuration =>
        {
            configuration.RootPath =  Configuration["WebApp:SourcePath"];
        }); 
        #endregion

        #region KeyCloak Integration
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;               
        })
        .AddCookie("Cookies")
        .AddOpenIdConnect(options =>
        {   
            SetOIDCConfiguration(ref options, bool.Parse(Configuration["Authentication:OIDC:IsSecuredHTTP"])); 
        });             

        services.AddAuthorization(options =>
        {
            options.AddPolicy("Administrator", policy => policy.RequireClaim("role", "Administrator"));
            options.AddPolicy("User", policy => policy.RequireClaim("role", "User"));  
            options.AddPolicy("CanUploadResourceInCode", policy => policy.RequireClaim("role", "User" , "Administrator"));      
        });        
        #endregion

        #region Add Swagger
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = "Zementis Modeler", Version = "v1" });
        }); 
        #endregion

        #region Initialize clients in singleton service
        var pySrvLocation = Configuration["PyServiceLocation:srvurl"];
        string ToolHostURL = Configuration["Tool:Host"];
        services.AddSingleton<IConfiguration>(Configuration);
        services.AddSingleton<IPyNNServiceClient>(new PyNNServiceClient(Configuration));
        services.AddSingleton<IPyAutoMLServiceClient>(new PyAutoMLServiceClient(Configuration));
        services.AddSingleton<IBaseImageForWielding>(new BaseImageForWielding(Configuration));
        services.AddSingleton<IPyJupyterServiceClient>(new PyJupyterServiceClient(ToolHostURL));
        services.AddSingleton<IPyZMEServiceClient>(new PyZMEServiceClient(Configuration));
        services.AddSingleton<IZSModelPredictionClient>(new ZSModelPredictionClient(Configuration));      
        services.AddSingleton<IPyTensorServiceClient>(new PyTensorServiceClient(ToolHostURL,ContentDir));
        #endregion
    }

    #region Setup User Identity Provider (KeyCloak) configuration
    public void SetOIDCConfiguration(ref OpenIdConnectOptions options, bool NeedSecuredHttp = true)
    {

            options.Authority = Configuration["Authentication:OIDC:AuthorizationEndpoint"];
            options.ClientId = Configuration["Authentication:OIDC:ClientId"];
            options.RequireHttpsMetadata = NeedSecuredHttp;
            options.SaveTokens = false;
            options.ClientSecret = Configuration["Authentication:OIDC:ClientSecret"];
            options.GetClaimsFromUserInfoEndpoint = true;
            options.SignedOutRedirectUri = Configuration["Authentication:OIDC:SignOutRedirectURL"];
            options.ResponseType = Configuration["Authentication:OIDC:ResponseType"];
            options.ClaimActions.Add(new CustomClaimAction("role", "role", "user_roles", "User"));                  
            options.Events = new OpenIdConnectEvents
            {                       

                OnRedirectToIdentityProvider = redirectContext=>
                {
                    if(NeedSecuredHttp) redirectContext.ProtocolMessage.RedirectUri = redirectContext.ProtocolMessage.RedirectUri.Replace("http://", "https://", StringComparison.OrdinalIgnoreCase);
                    return Task.FromResult(0);
                },
                OnRemoteFailure = context =>
                {
                    context.HandleResponse();
                    context.Response.Redirect("/Account/Error?message=" + context.Failure.StackTrace);                           
                    return Task.FromResult(0);
                }                   
            };
    }
    #endregion
    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {           
        #region Add Log Factory -> You can update its behaviour from appsettings*.json configuration
        AddLogger(ref loggerFactory);     
        #endregion
        app.Use((context, next) =>
        {
            if (context.Request.Headers.TryGetValue(XForwardedPathBase, out StringValues pathBase))
            {
                context.Request.PathBase = new PathString(pathBase);

            }
            if(context.Request.Headers.TryGetValue(XForwardedProto, out StringValues proto))
            {
                context.Request.Scheme = proto;
            }               
            return next();
        });

        // below is the fix for angular app reload redirections          
        app.Use(async (context, next) =>
        {
            // Do work that doesn't write to the Response.
            await next.Invoke();
            // Do logging or other work that doesn't write to the Response.
            if (context.User.Identity.IsAuthenticated && context.Response.StatusCode == 404 && !context.Request.Path.Value.Contains("/api"))
            {

                context.Request.Path = new PathString("/index.html");
                await next.Invoke();
            }
            else 
            {                    
                context.Request.Path = new PathString("/");                    
            }                
        });


        app.Use(async (context, next) =>
        {
            context.Features.Get<IHttpMaxRequestBodySizeFeature>()
                .MaxRequestBodySize = 5368709120;

            var serverAddressesFeature = app.ServerFeatures.Get<Microsoft.AspNetCore.Hosting.Server.Features.IServerAddressesFeature>();
            var addresses = string.Join(", ", serverAddressesFeature?.Addresses);
            await next.Invoke();
        });

        app.UseDeveloperExceptionPage();


        app.UseForwardedHeaders(new ForwardedHeadersOptions
        {
            ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
        }); 

        app.UseStaticFiles();

        app.UseStaticFiles(new StaticFileOptions
        {
            FileProvider = new PhysicalFileProvider(ContentDir),
            RequestPath = "/data"
        });            

        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "ZMM API v1");
        }); 
        Console.WriteLine("*********************before authentication****************");
        app.UseAuthentication();
        Console.WriteLine("*********************after authentication****************");
        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller}/{action}/{id?}");

            routes.MapRoute(
                name: "train",
                template: "{controller}/{action}");

            routes.MapSpaFallbackRoute(
                name: "spa-fallback",
                defaults: new { controller = "Home", action = "Index" });
        });

        #region To start ng serve without building client ui
        string ClientUIDirectory = Configuration["WebApp:SourcePath"];
        if(ClientUIDirectory.Equals(string.Empty) || ClientUIDirectory == null) throw new Exception("Error : Please, configure WebApp:SourcePath in appsettings.Development.json"); 
        if(!System.IO.Directory.Exists(ClientUIDirectory)) throw new Exception("Error : It seems that Client (Angular UI) Source folder is not present; To resolve this issue, Please, checkout this folder from repository /src/App/ClientApp");
        app.UseSpa(spa =>
        {  
            spa.Options.SourcePath = ClientUIDirectory; 
            spa.UseAngularCliServer(npmScript: "start");
        });
        #endregion


    }
    private void AddLogger(ref ILoggerFactory loggerFactory)
    {
        var LogFileName = "Logs" + System.IO.Path.DirectorySeparatorChar + "ZMM-{Date}-" + Guid.NewGuid().ToString() + ".log";
        loggerFactory.AddFile(LogFileName);
    }

    private void InitContentDir(ref string DirPath)
    {       
        try
        {     
            DirPath = Directory.GetCurrentDirectory();
            if(DirPath.Contains("src")) 
            {
                int startIdx = Directory.GetCurrentDirectory().IndexOf("src");
                DirPath = Directory.GetCurrentDirectory().Substring(0, startIdx - 1);
                DirPath = $"{Directory.GetParent(DirPath)}/ZMOD";
            }
            else
            {
                DirPath = Directory.GetParent(DirPath).ToString() +"/ZMOD";
            }                

            System.Console.WriteLine(Directory.GetCurrentDirectory());
            if (!Directory.Exists(DirPath))
            {
                Directory.CreateDirectory(DirPath);
            }
            if (string.IsNullOrEmpty(DirectoryHelper.fileUploadDirectoryPath))
            {
                DirectoryHelper.fileUploadDirectoryPath = DirPath;
            }
            DirectoryCreator.CreateFolders(DirPath);
            Logger.Log(LogLevel.Information, "Initialize content directory : " + DirPath);
        }
        catch(Exception ex)
        {
            Logger.LogCritical("Initializing ZMOD directory " + ex.StackTrace);
        }
    }
}

}

keycloak页面中的myclient具有以下配置:

Client Protocol: openid-connect
Access Type: confidential
Standarad flow enabled: on
implicit flow enabled: on
direct grant acess enabled: on
service account enabled : on
authorization enebaled : on
root url: http://localhost:5000
valid redirect url: * , */*
base url :  http://localhost:5000
admin url :  http://localhost:5000

0 个答案:

没有答案