前言

之前,一直使用IdentityServer4作为.net core程序的外部身份认证程序,ID4的优点自不必说了,缺点就是缺乏完善的管理界面。

后来,学习java quarkus框架时,偶然遇到了keycloak,具备完善的管理界面,并且支持多个realms,和quarkus oidc结合非常完美,于是就思考能否用keycloak来控制.net core程序的身份认证。

准备工作

dotnet new webapi,创建一个默认的webapi项目

安装keycloak的docker版本,我这里使用mariadb来持久化keycloak的数据,贴出docker-compose文件如下:

version: '3'
services:
keycloak:
image: jboss/keycloak:9.0.3
environment:
KEYCLOAK_USER: admin
KEYCLOAK_PASSWORD: admin
DB_USER: keycloak
DB_PASSWORD: password
ports:
- 8180:8080 mariadb:
image: mariadb:10.4
command: ['--character-set-server=utf8','--collation-server=utf8_general_ci','--default-time-zone=+8:00']
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: keycloak
MYSQL_USER: keycloak
MYSQL_PASSWORD: password
volumes:
- mariadata:/var/lib/mysql volumes:
mariadata:

docker-compose up 启动keycloak,然后可以在 http://localhost:8180 访问管理界面。

不要使用默认的realm,新建一个realm,比如“test2”。

然后新建client,比如“webapi”,地址填写 http://localhost:5000, 就是asp.net core webapi程序即将运行的地址。

然后创建角色和用户。

代码编写

修改Controllers/WeatherForcastController.cs

在控制器类前面增加[Authorize], 并且修改反馈的内容,方便调试。

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; namespace WebApi1.Controllers
{
[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
}; private readonly ILogger<WeatherForecastController> _logger; public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
} [HttpGet]
public IEnumerable<string> Get()
{
var result = new List<string>();
foreach (var claim in User.Claims)
result.Add(claim.Type+": "+claim.Value); result.Add("username: " + User.Identity.Name);
result.Add("IsAdmin: " + User.IsInRole("admin").ToString());
return result;
}
}
}

注意12行。

修改startup.cs

 namespace WebApi1
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(); services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = "http://localhost:8180/auth/realms/test2";
options.RequireHttpsMetadata = false;
options.Audience = "account";
options.TokenValidationParameters = new TokenValidationParameters{
NameClaimType = "preferred_username"
}; options.Events = new JwtBearerEvents{
OnTokenValidated = context =>{
var identity = context.Principal.Identity as ClaimsIdentity;
var access = context.Principal.Claims.FirstOrDefault(p => p.Type == "realm_access");
var jo = JObject.Parse(access.Value);
foreach (var role in jo["roles"].Values()){
identity.AddClaim(new Claim(ClaimTypes.Role, role.ToString()));
}
return Task.CompletedTask;
}
};
});
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} //app.UseHttpsRedirection(); IdentityModelEventSource.ShowPII = true; app.UseRouting(); app.UseAuthentication();
app.UseAuthorization(); app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}

这里的代码是遇到几个坑并解决之后的结果,下面列举遇到的坑和解决方法:

1、使用postman获取token之后,访问资源仍提示401,查看具体错误信息是audience=account,但是我们根据各种教程设置为webapi(同client-id)

第25行,设置audience=account后解决。

到现在也不知道为啥keycloak返回的是account而不是client-id。

2、控制器中User.Identity.Name=null

这主要源于ClaimType名称的问题,keycloak返回的claims中,使用preferred_username来表示用户名,和asp.net core identity默认的不同

第26行,修改默认的Claim名称后,User.Identity.Name可以正常返回用户名。

3、控制器中无法获取角色信息

和用户名类似,也是因为ClaimType问题,keycloak返回的角色信息claim名称是realm_access,而且内容是一段json文本,需要解析处理。

第30行,OnTokenValidated 事件中对角色Claim进行转换,然后角色信息正常。

修改后就可以使用[Authorize(Roles="admin")]来保护控制器或者方法了。

最后列举WeatherForecastController 的Get方法返回的各种claims和其他信息

[
"exp: 1587544810",
"iat: 1587544510",
"jti: 72648e7f-3bb4-4db1-b866-33cc26a5e5a1",
"iss: http://localhost:8180/auth/realms/test2",
"aud: account",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: 8811d051-52a6-40fc-b7f3-15d949fb25cd",
"typ: Bearer",
"azp: webapi",
"session_state: a9fb6a90-368b-4619-8789-43e26c7f2b85",
"http://schemas.microsoft.com/claims/authnclassreference: 1",
"allowed-origins: http://localhost:5000",
"realm_access: {\"roles\":[\"offline_access\",\"admin\",\"uma_authorization\"]}",
"resource_access: {\"account\":{\"roles\":[\"manage-account\",\"manage-account-links\",\"view-profile\"]}}",
"scope: email profile",
"email_verified: false",
"preferred_username: admin",
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role: offline_access",
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role: admin",
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role: uma_authorization",
"username: admin",
"IsAdmin: True"
]

Keycloak & Asp.net core webapi 整合跳坑之旅的更多相关文章

  1. ionic + asp.net core webapi + keycloak实现前后端用户认证和自动生成客户端代码

    概述 本文使用ionic/angular开发网页前台,asp.net core webapi开发restful service,使用keycloak保护前台页面和后台服务,并且利用open api自动 ...

  2. Asp.net Core WebApi 使用Swagger做帮助文档,并且自定义Swagger的UI

    WebApi写好之后,在线帮助文档以及能够在线调试的工具是专业化的表现,而Swagger毫无疑问是做Docs的最佳工具,自动生成每个Controller的接口说明,自动将参数解析成json,并且能够在 ...

  3. Asp.net core WebApi 使用Swagger生成帮助页

    最近我们团队一直进行.net core的转型,web开发向着前后端分离的技术架构演进,我们后台主要是采用了asp.net core webapi来进行开发,开始每次调试以及与前端人员的沟通上都存在这效 ...

  4. ASP.NET Core WebAPI中的分析工具MiniProfiler

    介绍 作为一个开发人员,你知道如何分析自己开发的Api性能么? 在Visual Studio和Azure中, 我们可以使用Application Insight来监控项目.除此之外我们还可以使用一个免 ...

  5. Asp.net core WebApi 使用Swagger生成帮助页实例

    最近我们团队一直进行.net core的转型,web开发向着前后端分离的技术架构演进,我们后台主要是采用了asp.net core webapi来进行开发,开始每次调试以及与前端人员的沟通上都存在这效 ...

  6. asp.net core webapi之跨域(Cors)访问

    这里说的跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被当作 ...

  7. ASP.NET Core WebAPI 开发-新建WebAPI项目

    ASP.NET Core WebAPI 开发-新建WebAPI项目, ASP.NET Core 1.0 RC2 即将发布,我们现在来学习一下 ASP.NET Core WebAPI开发. 网上已经有泄 ...

  8. Asp.Net Core WebApi学习笔记(四)-- Middleware

    Asp.Net Core WebApi学习笔记(四)-- Middleware 本文记录了Asp.Net管道模型和Asp.Net Core的Middleware模型的对比,并在上一篇的基础上增加Mid ...

  9. ASP.Net Core WebApi几种版本控制对比

    版本控制的好处: (1)助于及时推出功能, 而不会破坏现有系统. (2)它还可以帮助为选定的客户提供额外的功能. API 版本控制可以采用不同的方式进行控制,方法如下: (1)在 URL 中追加版本或 ...

随机推荐

  1. Leetcode802-找到最终的安全状态(Python3)

    刚开始没思路,还以为是利用二维矩阵直接标记节点间的有向路径,最后循环遍历就能得到结果,结果最后发现方向是错的,之后看了大佬们写的代码,发现原来是用出度来实现节点是否安全的. 照着大佬们的思路重新写了一 ...

  2. testlink数据表分析

    创建一个项目test node_types: 节点类型,这是一个固定的表 rights: 权限表,用户的操作权限 role_rights: 角色和权限关系表 roles: 角色表 testprojec ...

  3. kioptrix靶机记录

    靶机地址:172.16.1.193 Kali地址:172.16.1.107 首页为Apache测试页,没看到有价值信息 尝试目录扫描: 点击查看: http://172.16.1.193/index. ...

  4. C# 基础知识系列- 13 常见类库介绍(二)日期时间类

    0. 前言 上一篇内容介绍了Console类和Math类,这篇内容着重介绍一下C#中时间日期的处理方式. 上一篇勘误: 上一篇中关于静态类没有构造函数,这一表述有误.正确的说法是C#中静态类不包含常规 ...

  5. search(7)- elastic4s-search-filter模式

    现在我们可以开始探讨ES的核心环节:搜索search了.search又分filter,query两种模式.filter模式即筛选模式:将符合筛选条件的记录作为结果找出来.query模式则分两个步骤:先 ...

  6. Elasticsearch 集群部署

    本文部署环境 $ cat /etc/redhat-release CentOS Linux release (Core) 部署前系统优化 $ /etc/security/limits.conf roo ...

  7. 一图了解redis

    了解redis,这一张图就够了,话不多说,看图: 版权所有,转载请注明出处,欢迎讨论交流

  8. php下载各种编辑器输出的内容到word中展示

    <?php/** * Created by PhpStorm. * User: 工作 * Date: 2018/1/11 * Time: 12:02 */ //连接数据库$dsn = " ...

  9. 20199310《Linux内核原理与分析》第十二周作业

    1.问题描述 2014年9月24日,Bash中发现了一个严重漏洞shellshock,该漏洞可用于许多系统,并且既可以远程也可以在本地触发.在本实验中,通过学习重现攻击该漏洞,加深对于ShellSho ...

  10. Zabbix备份数据文件

    mysql自带的工具mysqldump,当数据量大了之后进行全备所花的时间比较长,这样将会造成数据库的锁读.从而zabbix服务的监控告警不断,想着做下配置文件的备份.刚好有这么个脚本.满足了需求. ...