前言

之前,一直使用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. windows批处理protoc生成C++代码

    1 首先需要生成protoc的可执行文件,具体可以参考  https://www.cnblogs.com/cnxkey/articles/10152646.html 2 将单个protoc文件生成.h ...

  2. cmd命令行中查看、修改、删除与添加环境变量

    注意:只在当前窗口生效!! 1.查看当前所有可用的环境变量:输入 set 即可查看. set 2.查看某个环境变量:输入 “set 变量名”即可 set python 3.修改环境变量 :输入 “se ...

  3. 使用mysqlbinlog查看二进制日志

    (一)mysqlbinlog工具介绍 binlog类型是二进制的,也就意味着我们没法直接打开看,MySQL提供了mysqlbinlog来查看二进制日志,该工具类似于Oracle的logminer.my ...

  4. 理解java容器底层原理--手动实现HashMap

    HashMap结构 HashMap的底层是数组+链表,百度百科找了张图: 先写个链表节点的类 package com.xzlf.collection2; public class Node { int ...

  5. C#客户端打印条形码

    第一种方法: 引用第三方插件文件zxing.dll // 1.设置条形码规格 EncodingOptions encodeOption = new EncodingOptions(); encodeO ...

  6. 对 spring 中默认的 DataSource 创建进行覆盖

    配置如下 /** * Primary:标识为主配置,将默认的配置覆盖掉 * ConfigurationProperties:设置配置来源 * * @return DataSource */ @Prim ...

  7. hexo-themes-setting

    hexo-themes-setting hexotheme Hexo 主题配置管理 一半有几种方式, 可以删除git 单独维护 也可以使用 hexo 推荐的方式进行维护 所有需要写在主题配置文件中的配 ...

  8. 在java中构建高效的结果缓存

    文章目录 使用HashMap 使用ConcurrentHashMap FutureTask 在java中构建高效的结果缓存 缓存是现代应用服务器中非常常用的组件.除了第三方缓存以外,我们通常也需要在j ...

  9. 某拍sig算法揭秘---50行代码下载5000万小姐姐自拍小视频

    背景: ​ ​ ​ 首先我们需要一点点python基础,比如可以运行类似下面的代码 import requests headers={ "xxx":"xxx", ...

  10. css-position之fixed vs sticky

    css-position之fixed  vs sticky fixed(固定定位) 元素相对于浏览器窗口是固定的,即使是窗口滚动,元素也是固定的 sticky(粘性定位) 基于用户滚定动来进行定位的, ...