前言

之前,一直使用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. 计算机系统基础学习笔记(1)-基本GCC,objdump,GBD命令的使用

    基本GCC命令的使用 GCC是一套由GNU项目开发的编程语言编译器,可处理C语言. C++.Fortran.Pascal.Objective-C.Java等等.GCC通常是 跨平台软件的编译器首选.g ...

  2. 小小小小小flag

    2020:300道题 小小小小小flag 150红题 100道橙题 50道黄题 努力变强!加油 我的主页: 主页https://www.luogu.com.cn/user/306734 谢谢大家,目前 ...

  3. 3. JS生成32位随机数

    function randomWord ( randomFlag,min,max ) { var str = " ", range = min, arr = ['0','1','2 ...

  4. [GO] mac安装GO 初次尝试

    其实试了好多方法,我用的是下面这种方法,简单快捷! 安装homebrew 在终端输入命令 ruby -e "$(curl -fsSL https://raw.githubuserconten ...

  5. XSS Cheat Sheet(basics and advanced)

    XSS Cheat Sheet BASICS HTML注入 当输入位于HTML标记的属性值内或标记的外部(下一种情况中描述的标记除外)时使用.如果输入在HTML注释中,则在payload前加上&quo ...

  6. php +go关键字实现协程

    来源: https://studygolang.com/articles/17631?fr=sidebar 今天在知乎浏览时忽然发现了一个有趣的东西,php竟然可以实现协程的实现,而且还是通过go关键 ...

  7. 刚听完CSDN总裁蒋涛先生的学术报告

    主题: 二十年程序人生和我的人才观 第一次参加所谓的"学术报告", 但感觉更多的是蒋总在跟我们分享他个人的成长经验. 按蒋总的话说, 他已经从2000年开始不碰怎么技术了, 所以个 ...

  8. 搭建vsftpd文件服务器并创建虚拟用户

    一.安装     1. 查看是否安装vsftpd         rpm -qa | grep vsftpd     2. 安装          yum -y install vsftpd      ...

  9. php安装igbinary扩展(windows)

    pecl.php.net 是php的扩展仓库,访问此网站后,搜索需要安装的扩展,截图如下: igbinary: http://pecl.php.net/package/redis github的网址: ...

  10. NetCore项目实战篇02---全局异常处理

    在 .netcore中可以自定义自己的异常类型,步骤如下: 1.自定义自己的异常类型UserOperationException 并继承自Exception public class UserOper ...