ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

keycloak~uma远程资源授权对接asp.net core

2021-11-18 17:34:29  阅读:223  来源: 互联网

标签:core asp services token uma context var configuration options


官方的keycloak的适配器并没有提供.net版本的,所以我们需要自己去实现一下,目前打算把资源服务器对接KC之后,让资源服务器的API接口通过KC的UMA授权方式来管理起来,所以需要对这个功能进行开发,springboot版本官方已经实现,.net core版本我们自己实现了一下,对UMA授权不清楚的同学可以先看我这篇文章《keycloak~授权功能的使用》。

  • 添加标准的依赖包
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.13" />
  • 如果你只用kc做认证,授权自己去实现,你可以直接引用OIDC包,然后对OIDC产生的token进行解析,拿到kc颁发的角色即可
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="3.1.13" />
  • OIDC方式,本例子中的实现,当用户没有登录时,会重定向到KC登录页进行认证
        /// <summary>
        /// OIDC认证
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <param name="scopes"></param>
        /// <returns></returns>
        public static AuthenticationBuilder addKcOidc(this IServiceCollection services, IConfiguration configuration, ICollection<string> scopes)
        {
            return services.AddAuthentication(options =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            })
              .AddCookie()//开启cookie的支持
              .AddOpenIdConnect(options =>
            {
                options.Authority = configuration["Oidc:Authority"];
                options.ClientId = configuration["Oidc:ClientId"];
                options.ClientSecret = configuration["Oidc:ClientSecret"];
                options.SaveTokens = true;
                options.ResponseType = OpenIdConnectResponseType.CodeIdTokenToken;
                options.RequireHttpsMetadata = false;
                options.GetClaimsFromUserInfoEndpoint = true;
                options.SaveTokens = true;
                options.Scope.Clear();
                foreach (var scope in scopes)
                {
                    options.Scope.Add(scope);
                }

                options.Events = new OpenIdConnectEvents
                {

                    OnTokenValidated = context =>
                    {
                        //获取到了id_token
                        var identity = context.Principal.Identity as ClaimsIdentity;

                        var token = context.ProtocolMessage.AccessToken;
                        if (token != null)
                        {
                            var payload = token.Split(".")[1];
                            string payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));
                            JObject json = JObject.Parse(payloadJson);

                            if (json.ContainsKey("realm_access"))
                            {
                                var access = json["realm_access"].Values();
                                foreach (var role in access.Values())
                                {
                                    identity.AddClaim(new Claim(ClaimTypes.Role, role.ToString()));
                                }

                            }
                            // 客户端角色

                            if (json.ContainsKey("resource_access"))
                            {
                                var access = json["resource_access"].Values();
                                foreach (var role in access["roles"].Values())
                                {
                                    identity.AddClaim(new Claim(ClaimTypes.Role, role.ToString()));
                                }
                            }
                        }

                        return Task.CompletedTask;
                    },
                    OnTokenResponseReceived = context =>
                    {
                        return Task.CompletedTask;
                    },
                };


            });
        }
  • UMA远程授权,本例子中,当用户访问接口时,没有带着token,将返回401,如果token没有权限将返回403
/// <summary>
        /// uma远程资源
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <param name="scopes"></param>
        /// <returns></returns>
        public static AuthenticationBuilder addKcUma(this IServiceCollection services, IConfiguration configuration)
        {
            return services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
            {
                options.Authority = configuration["Oidc:Authority"];
                options.Audience = configuration["Oidc:ClientId"];
                options.IncludeErrorDetails = true;
                options.RequireHttpsMetadata = false;
                options.SaveToken = true;
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateAudience = false,
                    ValidateIssuer = true,
                    ValidIssuer = configuration["Oidc:Authority"],
                    ValidateLifetime = false
                };

                options.Events = new JwtBearerEvents
                {


                    OnTokenValidated = context =>
                    {
                        //获取到了id_token
                        var identity = context.Principal.Identity as ClaimsIdentity;

                        if (context.Request.Headers.ContainsKey(AuthName))
                        {
                            var token = context.Request.Headers[AuthName].ToString();
                            if (token != null)
                            {
                                var provider = services.BuildServiceProvider();//get an instance of IServiceProvider
                                var clientFactory = provider.GetService<IHttpClientFactory>();
                                string uma = getUmaToken(clientFactory, options.Authority, options.Audience, token).Result;
                                // 客户端所拥有的资源
                                List<UmaResource> umaResources = getUmaPermissions(uma);
                                // 本服务器的所有资源
                                List<string> allResources = getServerUmaPermissions(clientFactory, options.Authority, options.Audience, configuration["Oidc:ClientSecret"]).Result;
                                // 过滤本服务器的资源
                                umaResources = umaResources.Where(i => allResources.Contains(i.rsid)).ToList();
                                // 当前url
                                string currentUrl = context.Request.Path;
                                foreach (UmaResource item in umaResources)
                                {
                                    // 校验当前url是否在客户端授权的url中
                                    List<string> urls = getUmaUrls(clientFactory, options.Authority, item.rsid, token).Result;
                                    foreach (string url in urls)
                                    {
                                        if (url.EndsWith("*"))
                                        {
                                            if (currentUrl.Contains(url.TrimEnd('*')))
                                                return Task.CompletedTask;
                                        }
                                        else
                                        {
                                            if (url.Equals(currentUrl))
                                                return Task.CompletedTask;
                                        }
                                    }

                                }
                            }
                        }
                        var payload = JsonConvert.SerializeObject(new { Code = "403", Message = "很抱歉,您无权访问该接口" });
                        context.Response.ContentType = "application/json";
                        context.Response.StatusCode = StatusCodes.Status403Forbidden;
                        context.Response.WriteAsync(payload);
                        return Task.FromResult(0);
                    }


                };

            });


        }

  • 在startup中去注册我们的认证方式
public void ConfigureServices(IServiceCollection services)
{
           
            services.AddControllers();
            services.addKcUma(Configuration);
            services.AddAuthorization();
            services.AddHttpClient();
}
  • 未认证的资源将出现403的结果

标签:core,asp,services,token,uma,context,var,configuration,options
来源: https://www.cnblogs.com/lori/p/15573380.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有