前言

之前,一直使用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. 深度学习之文本分类模型-前馈神经网络(Feed-Forward Neural Networks)

    目录 DAN(Deep Average Network) Fasttext fasttext文本分类 fasttext的n-gram模型 Doc2vec DAN(Deep Average Networ ...

  2. JavaScript的运行机制!!!很重要很重要!!!!!!请看大神操作!

    https://juejin.im/post/59e85eebf265da430d571f89

  3. 处理时间的类 —— System类、Date类 、SimpleDateFormat类 与 Calendar类

    在我们以往的编程中,就有过通过运行前和运行后时间差来判断时间复杂度的例子,再扯得远一点,我们在C语言中制造随机数的操作,也要用到有关时间的函数.而且,在我们未来的编程中,也会时不时要用到能够读取当前时 ...

  4. 详解 Lambda表达式

    Lambda表达式 概述: Lambda 是一个匿名函数, 我们可以把 Lambda表达式理解为是一段可以传递的代码 (将代码像数据一样进行传递) 可以写出更简洁.更灵活的代码. 作为一种更紧凑的代码 ...

  5. Python 七步捉虫法

    了解一些技巧助你减少代码查错时间. -- Maria Mckinley 在周五的下午三点钟(为什么是这个时间?因为事情总会在周五下午三点钟发生),你收到一条通知,客户发现你的软件出现一个错误.在有了初 ...

  6. Mac安装aws-cli全过程,通过命令行上传文件到aws s3协议服务器

    第一次使用aws,首先查询了各种资料,我第一步需要做的是安装aws-cli,而安装aws-cli之前需要安装python3,当然你安装python3之前你还需要安装homebrew,当然我正在安装的过 ...

  7. <string>头文件常用成员函数

    之前说过 string和vector一样,也是一种顺序容器,并且它也自带成员函数,用法和vector的成员函数差不多,不过它只能用来存放字符,也就是字符串. 在c++中,<string>基 ...

  8. 哈希Hash定义

    Hash,一般翻译做"散列”,也有直接音译为"哈希"的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值. ...

  9. MarkDown排版测试

    1.标题设置 标题(大标题) 标题(小标题) 标题(一级标题) 标题( 二级标题) 标题(三级标题) 标题(四级标题) 备注:大标题与一级标题一样,小标题与二级标题一样,"#"前无 ...

  10. WANNACRY病毒中的加密技术分析

    WANNACRY病毒中的加密技术分析 2019/11/6 16:56:46 分析WANNACRY病毒中的加解密技术的应用.分析内容包括但不限于:对称密码技术和公钥密码技术的作用:受害者支付赎金后就会恢 ...