IdentityServer:检查 OpenId Connect 中的身份验证策略中是不是存在范围

Posted

技术标签:

【中文标题】IdentityServer:检查 OpenId Connect 中的身份验证策略中是不是存在范围【英文标题】:IdentityServer: Check if scopes present in a policy for authentication in OpenId ConnectIdentityServer:检查 OpenId Connect 中的身份验证策略中是否存在范围 【发布时间】:2021-09-27 05:22:38 【问题描述】:

有2个项目:

1. IdentityServer project
2. Client Project

在我的客户项目中,我有一个具有基于策略的身份验证的控制器:

[ApiController]
[Route("[controller]")]
[Authorize(Policy ="SomePolicy")]
public class BankController : ControllerBase

...    

在客户端项目的 Startup.cs 中,我添加了策略身份验证代码,该代码表示​​令牌应包含值为“fullaccess”的“范围”。见以下代码:

services.AddAuthorization(options =>

    options.AddPolicy("SomePolicy", policy =>
    
        policy.RequireClaim("scope", "fullaccess");
    );
);

“完全访问”是在 IdentityServer 项目的 appsetting.json 上定义的 ApiScope。

"IdentityServerSettings": 
  "ApiScopes": [
    
      "Name": "fullaccess"
    
  ],
  ...

代码在邮递员测试中运行良好。

现在我通过添加行 options.Scope.Add("fullaccess"); 在我的客户项目上的 OIDC 上添加了这个范围,请参见下面的代码。

.AddOpenIdConnect("oidc", options =>

     options.Authority = "https://localhost:5001";
     options.ClientId = "postman";
     options.ResponseType = "code";
     
     //adding fullaccess scope
     options.Scope.Add("fullaccess");

     options.SaveTokens = true;
 );

现在我尝试在浏览器上输入 BankController。这个控制器受我创建的这个策略的保护。会发生以下情况:

    我被重定向到 IdentityServer 登录页面。 然后我登录,在此 IdentityServer 将我重定向回 BankController 之后。 现在代替银行控制器显示内容。我被重定向到 AccessDenied,因为“fullaccess”范围似乎不存在,但为什么呢?

控制台显示如下错误:

Authorization failed. These requirements were not met:
ClaimsAuthorizationRequirement:Claim.Type=scope and Claim.Value is one of the following values: (fullaccess)

如何解决?

【问题讨论】:

控制台或浏览器是否有错误信息? @TinyWang 没有错误。 嗨,@yogihosting,请允许我在下面发布我的编程步骤,因为我们找不到错误。希望它可以帮助您集成身份服务器4 :) 有进展吗?还有什么问题还是根本没用? @TinyWang 没有进展。我在问题上添加了更多内容(以及控制台上的错误)。请看一看。 【参考方案1】:

我想我可以在这里分享我的集成步骤来帮助您解决问题。

点击这里查看related blog。

首先,我创建了一个 asp.net core 3.1 mvc 项目,并安装了这些包:

<ItemGroup>
    <PackageReference Include="IdentityServer4" Version="4.1.2" />
    <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
    <PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="3.1.17" />
  </ItemGroup>

然后添加一个名为 Config.cs 的文件,请注意在我的项目中,https 的默认端口是 5001,请参阅launchSetting.json:

using IdentityModel;
using IdentityServer4;
using IdentityServer4.Models;
using IdentityServer4.Test;
using System.Collections.Generic;
using System.Security.Claims;

namespace WebApplication1

    public class Config
    
        public static IEnumerable<IdentityResource> GetIdentityResources()
        
            return new List<IdentityResource>
            
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
                new IdentityResource
                
                    Name = "role",
                    UserClaims = new List<string> "role"
                
            ;
        

        public static IEnumerable<ApiScope> GetApiScopes()
        
            return new List<ApiScope>
            
                new ApiScope("api1.read", "Read Access to API #1"),
                new ApiScope("api1.write", "Write Access to API #1")
            ;
        

        public static IEnumerable<ApiResource> GetApiResources()
        
            return new List<ApiResource> 
                new ApiResource
                
                    Name = "api1",
                    DisplayName = "API #1",
                    Description = "Allow the application to access API #1 on your behalf",
                    Scopes = new List<string> "api1.read", "api1.write",
                    ApiSecrets = new List<Secret> new Secret("ScopeSecret".Sha256()),
                    UserClaims = new List<string> "role"
                
            ;
        

        public static IEnumerable<Client> GetClients()
        
            return new List<Client>
            
                // other clients omitted...

                new Client
                
                    ClientId = "oidcClient",
                    ClientName = "Example Client Application",
                    ClientSecrets = new List<Secret> new Secret("SuperSecretPassword".Sha256()), // change me!
    
                    AllowedGrantTypes = GrantTypes.Code,
                    RedirectUris = new List<string> "https://localhost:5001/signin-oidc",
                    AllowedScopes = new List<string>
                    
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
                        IdentityServerConstants.StandardScopes.Email,
                        "role",
                        "api1.read"
                    ,

                    RequirePkce = true,
                    AllowPlainTextPkce = false
                ,
                new Client
                
                    ClientId = "oauthClient",
                    ClientName = "Example client application using client credentials",
                    AllowedGrantTypes = GrantTypes.ClientCredentials,
                    ClientSecrets = new List<Secret> new Secret("SuperSecretPassword".Sha256()), // change me!
                    AllowedScopes = new List<string> "api1.read"
                
            ;
        

        public static List<TestUser> GetUsers()
        
            return new List<TestUser>
            
                new TestUser 
                    SubjectId = "5BE86359-073C-434B-AD2D-A3932222DABE",
                    Username = "tiny",
                    Password = "111",
                    Claims = new List<Claim> 
                        new Claim(JwtClaimTypes.Email, "tiny@gmail.com"),
                        new Claim(JwtClaimTypes.Role, "admin")
                    
                
            ;
        
    

接下来,我们可以使用 powershell 运行命令在我们的项目中为登录部分安装默认的identity server 4 ui。因为它还会提供一个 HomeController.cs,所以我们可以在创建项目时重命名或删除原来的 HomeController。进入项目根目录,打开powershell运行:

iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/IdentityServer/IdentityServer4.Quickstart.UI/main/getmain.ps1'))

然后我们需要修改startup.cs,这是我的文件:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Threading.Tasks;

namespace WebApplication1

    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.AddIdentityServer()
                .AddDeveloperSigningCredential()
                .AddInMemoryIdentityResources(Config.GetIdentityResources())
                .AddInMemoryApiResources(Config.GetApiResources())
                .AddInMemoryApiScopes(Config.GetApiScopes())
                .AddInMemoryClients(Config.GetClients())
                .AddTestUsers(Config.GetUsers());
            services.AddControllersWithViews();

            //If we only need to enable the token validation for api, use the code commented below
            //services.AddAuthentication("Bearer")
            //.AddIdentityServerAuthentication("Bearer", options =>
            //
            //    options.ApiName = "api1";
            //    options.Authority = "https://localhost:5001";
            //);

            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
            services.AddAuthentication(options =>
            
                options.DefaultScheme = "cookie";
                options.DefaultChallengeScheme = "oidc";
            )
            .AddCookie("cookie")
            .AddOpenIdConnect("oidc", options =>
            
                options.Authority = "https://localhost:5001";
                options.ClientId = "oidcClient";
                options.ClientSecret = "SuperSecretPassword";

                options.ResponseType = "code";
                options.UsePkce = true;
                options.ResponseMode = "query";

                options.CallbackPath = "/signin-oidc"; // default redirect URI

                // options.Scope.Add("oidc"); // default scope
                // options.Scope.Add("profile"); // default scope
                options.Scope.Add("api1.read");
                options.SaveTokens = true;
            );
        

        // 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();
            
            else
            
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            
            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseIdentityServer();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "controller=Home/action=Index/id?");
            );
        
    

最后,让我们在 HomeController 中注释 [AllowAnonymous] 属性并为隐私页面添加一个操作:

[Authorize]
public IActionResult Privacy() => View();

我们还可以添加一个新的控制器,使其像 api 一样工作,并在该控制器上添加 [Authorize],例如

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace WebApplication1.Controllers

    [Authorize]
    public class HelloController : Controller
    
        public string Index()
        
            return "hello world";
        
    

然后启动程序,我们可以直接看到主页,但是如果我们访问https://localhost:5001/hello/indexhttps://localhost:5001/home/privacy,它会重定向到一个登录页面,登录后(用户名和密码在config.cs中定义) 我们可以看到私人页面或响应消息。

【讨论】:

不,我的授权属性是 [Authorize(Policy ="SomePolicy")] 而不是 [Authorize]

以上是关于IdentityServer:检查 OpenId Connect 中的身份验证策略中是不是存在范围的主要内容,如果未能解决你的问题,请参考以下文章

IdentityServer4- 使用OpenID Connect添加用户身份验证(implicit)

IdentityServer4专题之二:OpenID介绍

IdentityServer3——入门教程:.NET开源OpenID Connect 和OAuth解决方案IdentityServer v3 术语

IdentityServer4 well-known/openid-configuration

IDX20803:无法从以下位置获取配置:“https://localhost/IdentityServer/Core/.well-known/openid-configuration”

授权认证(IdentityServer4)