zoukankan      html  css  js  c++  java
  • ASP.NET Core的无状态身份认证框架IdentityServer4

    Identity Server 4是IdentityServer的最新版本,它是流行的OpenID Connect和OAuth Framework for .NET,为ASP.NET Core和.NET Core进行了更新和重新设计。认证原理基于JWT,符合JWT流程。关于Identity Server 4的介绍和使用,网上已经很多了,一搜一大堆,本篇文章就不在介绍,这里有几篇文章还不错,作为一个参考:

    1,《ASP.NET Core的身份认证框架IdentityServer4--入门》,这篇文章是翻译的国外的一篇文章,对于入门很有启发,英文原文地址:https://www.scottbrady91.com/Identity-Server/Getting-Started-with-IdentityServer-4

    2,《使用JWT搭建分布式无状态身份认证系统》,这篇文章介绍JWT,以及怎么不引用Identity Server 4,手动写JWT认证服务。了解一下JWT原理和代码实现即可,如果在实际项目中用,不必再“造轮子”。

    3,《IdentityServer4 中文文档与实战》,这是按照官方文档来研究的系列文章,从入门到实践。

    本篇文章使用的环境:VS2017,15.9.11,目标框架:.NET Core 2.2

    在项目中使用的步骤:

    1,新建一个空的解决方案

    2,在解决方案里新建项目,选择ASP.NET Core Web应用程序

    3,目标框架选择 Core 2.2 (或其他的Core版本),选择“应用程序(模型视图控制器)”

    4,打开项目属性,选择“调试”选项,删除默认的启动项

     

    5,创建一个新的启动项,名称定为:WebAPPHost,把端口指定到5002(或者其他不与本地冲突的端口)

     

    6,生成的launchSettings.json如下

    {
    "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
    "applicationUrl": "http://localhost:31509",
    "sslPort": 44328
    }
    },
    "profiles": {
    "WebAppHost": {
    "commandName": "Project",
    "launchBrowser": false,
    "environmentVariables": {
    "ASPNETCORE_ENVIRONMENT": "Development"
    },
    "applicationUrl": "http://localhost:5002"
    }
    }

     

     7,删除不必要的文件、文件夹。(作为服务提供的项目,只提供API接口,不需要页面)

     

    8,在NuGet中引入IdentityServer 4 

    9,新建一个文件夹IdentityServer,用于放IdentityServer相关的文件。

     9.1首先创建一个IdentityServerClients类,定义两个方法:IEnumerable<Client> GetClients() 和 List<TestUser> GetTestUsers()

    GetClients方法是IdentityServer客户端(访问控制列表)集合,GetTestUsers方法是定义IdentityServer的测试用户。代码如下:

     1 public class IdentityServerClients
     2     {
     3         /// <summary>
     4         /// IdentityServer客户端(访问控制列表)
     5         /// </summary>
     6         /// <returns></returns>
     7         public static IEnumerable<Client> GetClients()
     8         {
     9             var list = new List<Client>
    10             {
    11                 new Client
    12                 {
    13                     ClientId = "client",
    14                     AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
    15                     AllowedScopes = {"WebAppAPI" },//添加允许访问API范围
    16                     AllowOfflineAccess = true,
    17                     AccessTokenLifetime = 60 * 60,
    18                     RefreshTokenExpiration = TokenExpiration.Sliding,
    19                     SlidingRefreshTokenLifetime = 60 * 30,
    20                     RefreshTokenUsage = TokenUsage.ReUse,
    21                     ClientSecrets =
    22                     {
    23                         new Secret("D7896FC26CAC97942DEF0402322524BB".Sha256())
    24                     }
    25                 }
    26             };
    27 
    28             return list;
    29         }
    30 
    31         /// <summary>
    32         /// IdentityServer的测试用户
    33         /// </summary>
    34         /// <returns></returns>
    35         public static List<TestUser> GetTestUsers()
    36         {
    37             List<TestUser> Testers = new List<TestUser>()
    38             {
    39                 new TestUser()
    40                 {
    41                     SubjectId = "1",
    42                     Password ="111111",
    43                     Username = "admin001"
    44                 },
    45                 new TestUser()
    46                 {
    47                     SubjectId = "2",
    48                     Password ="222222",
    49                     Username = "admin002"
    50                 }
    51             };
    52 
    53             return Testers;
    54         }
    55     }
    View Code

    9.2 创建一个IdentityServerResources类,定义IdentityServer认证的Resources,代码如下: 

     1 public class IdentityServerResources
     2     {
     3         /// <summary>
     4         /// 创建允许访问的API资源
     5         /// </summary>
     6         /// <returns></returns>
     7         public static IEnumerable<ApiResource> GetApiResources()
     8         {
     9             List<ApiResource> resources = new List<ApiResource>()
    10             {
    11                 new ApiResource("WebAppAPI", "测试的API"),//定义API的访问范围名称(Scope)
    12             };
    13 
    14             return resources;
    15         }
    16 
    17         /// <summary>
    18         /// 创建认证的资源
    19         /// </summary>
    20         /// <returns></returns>
    21         public static IEnumerable<IdentityResource> GetIdentityResources()
    22         {
    23             return new List<IdentityResource>
    24             {
    25                 new IdentityResources.OpenId(),
    26                 new IdentityResources.Profile(),
    27                 new IdentityResources.Email(),
    28                 new IdentityResources.Address(),
    29                 new IdentityResources.Phone()
    30             };
    31         }
    32     }
    View Code

     9.3 创建一个ResourceOwnerPasswordValidator类,这个类的作用是自定义用户登录:从自己的数据库中验证用户,或者其它项目验证用户。

    一个例子:假设项目的用户数据库在别处,并且有登录接口,就可以在这个自定义类中写相应的逻辑来实现。

    这个类需要继承IResourceOwnerPasswordValidator接口,才能实现自定义登录。代码如下:

     1 public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
     2     {
     3         public ResourceOwnerPasswordValidator()
     4         {
     5 
     6         }
     7 
     8         /// <summary>
     9         /// Validates the resource owner password credential
    10         /// </summary>
    11         /// <param name="context"></param>
    12         /// <returns></returns>
    13         public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
    14         {
    15             await Task.Run(() =>
    16             {
    17                 //在此处编写自己的账号密码验证逻辑,若验证通过,写入context的Result,告诉IdentityServer4账号密码是合法的,否则,不添加。
    18                 var userId = "1";
    19                 context.Result = new GrantValidationResult(userId, OidcConstants.AuthenticationMethods.Password, DateTime.UtcNow);
    20             });
    21         }
    22     }
    View Code

     创建完成后,我们的IdentityServer文件夹里有三个类:IdentityServerClients.cs,IdentityServerResources.cs,ResourceOwnerPasswordValidator.cs。

    在IdentityServer4中还有其他功能可供使用,根据项目实际需求,可以集中放到这个文件夹内。 

    10,在Startup.cs文件中,引入IdentityServer4服务、配置JWT,以及告诉我们项目允许IdentityServer开始拦截路由并处理请求。

    10.1,在ConfigureServices() 中引入IdentityServer4服务。在这里配置IdentityServer的测试用户,或者是自定义用户登录。

    当同时设置了测试用户和自定义用户登录,那么IdentityServer是按照测试用户为主的。

    1 services.AddIdentityServer()//Ids4服务
    2                 .AddDeveloperSigningCredential()
    3                 .AddInMemoryApiResources(IdentityServerResources.GetApiResources())
    4                 .AddInMemoryIdentityResources(IdentityServerResources.GetIdentityResources())
    5                 .AddInMemoryClients(IdentityServerClients.GetClients())//把配置文件的Client配置资源放到内存
    6                 //.AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()//自定义用户登录。即自定义用户登录又添加测试用户,则以测试用户为准
    7                 .AddTestUsers(IdentityServerClients.GetTestUsers())//添加测试用户
    8                 ;
    View Code

    10.2,在ConfigureServices() 中配置JWT服务

     1 //重写JWT,如果不配置JWT,那么IdentityServer4会在未认证身份的时候重定向到Account/Login,从而出错
     2             JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
     3             services.AddAuthentication("Bearer")
     4               .AddJwtBearer("Bearer", options =>
     5               {
     6                   options.Authority = Configuration["JWT:Authority"];
     7                   options.RequireHttpsMetadata = false;
     8                   options.Audience = "WebAppAPI";
     9                   options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(0);
    10                   options.TokenValidationParameters.RequireExpirationTime = true;
    11               });
    View Code

     10.3,在Configure() 方法中添加以下内容以将IdentityServer中间件添加到HTTP管道

    1 app.UseCors("default");
    2 //允许IdentityServer开始拦截路由并处理请求。
    3 app.UseIdentityServer();
    4 //添加身份验证UseMvc
    5 app.UseAuthentication();

    10.4,在appsettings.json中加入JWT服务地址,以告诉IdentityServer去哪里寻找JWT服务,端口与我们在第5步,创建WebAPPHost时一致,appsettings.json文件代码如下

     1 {
     2   "Logging": {
     3     "LogLevel": {
     4       "Default": "Warning"
     5     }
     6   },
     7   "JWT": {
     8     "Authority": "http://localhost:5002"
     9   },
    10   "AllowedHosts": "*"
    11 }

     11,改造我们的Controller,增加身份认证。

    11.1,创建一个基类控制器:AuthorizeController.cs,控制器中暂时没有内容,只加入一个身份验证的类标签:[Authorize],代码如下

    1 [Authorize]
    2 public class AuthorizeController : Controller
    3 {
    4 
    5 }

    当以后需要在所有控制器中做公共的事情,就可以在这个控制器中增加逻辑代码。

    11.2,IdentityServer4身份认证已结束,我们把HomeController当做一个测试控制器,修改一下用于测试:

    1 public class HomeController : AuthorizeController
    2 {
    3     [HttpGet]
    4     public string Index()
    5     {
    6         var result = "{"detail":"Hello Word!"}";
    7         return result;
    8     } 
    9 }

    12,运行起来,获取token的地址是:http://localhost:5002/connect/token,这是一个标准的获取token接口,无论域名时什么,地址是不变的。

    body提交的参数分别是:

    grant_type:password

    username:admin001

    password:111111

    scope:WebAppAPI

    client_id:client

    client_secret:D7896FC26CAC97942DEF0402322524BB

    然后,我们用获取到的token访问home/index接口

     

     

     若不加token访问是被拦截的,返回401:

  • 相关阅读:
    【原创】贴片电容的测量方法。。。这是我从自己QQ空间转过来的,本人实操!
    CentOS6.4安装Apache+MySQL+PHP
    第一次在博客园写博客。。。新人
    C# 简单生成双色球代码
    从客户端中检测到有潜在危险的 Request.Form 值 方法
    经典实例
    js鼠标键禁用功能
    逻辑思维题
    C#运算符笔记
    C#基础
  • 原文地址:https://www.cnblogs.com/huyueping/p/11170174.html
Copyright © 2011-2022 走看看