.Net Core WebApi 2.0使用Oauth2 + IdentityServer4进行身份认证

直接上代码,该说明的我都把注释写在代码中了

 

逻辑图如下:


 

 

一、创建WebApi(用于IdentityServer4发送token和验证token)(IdentityServerSolution)

1.nuget安装identityServer4(最新版必须是.net core3.0才可以,我是2.0,所以装不了最新版的):

Install-Package IdentityServer4 -version 2.5.4

2.创建Config类:配置资源和客户端(家里哪些东西可以被访问,以及客户端得满足什么条件才可以访问)

using IdentityServer4.Models;
using System.Collections.Generic;

namespace IdentityServerSolution
{
    public class Config
    {
        /// <summary>
        /// 允许访问哪些Api(就像我允许我家里的哪些东西可以让顾客访问使用,如桌子,椅子等等)   CreateDate:2019-12-26 14:08:29;Author:Ling_bug
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<ApiResource> GetApiResources()
        {
            return new[]
            {
                new ApiResource("api1", "Lingbug Api1"),
                new ApiResource("api2", "Lingbug Api2")
            };
        }

        /// <summary>
        /// 允许哪些客户端访问(就像我要求顾客必须具备哪些条件才可以拿到进入我家的钥匙)   CreateDate:2019-12-26 14:09:51;Author:Ling_bug
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>
            {
                new Client
                {
                    //对应请求参数的client_id(假设身高)
                    ClientId = "Client",
                    //对应请求参数的grant_type(GrantTypes.ClientCredentials是client_credentials)(假设体重)
                    AllowedGrantTypes = GrantTypes.ClientCredentials,
                    //对应请求参数的client_secret(假设口令)
                    ClientSecrets =
                    {
                        new Secret(Encrypt("secret")),
                    },
                    //对应请求参数的Scope,这里写的类似于一个id,对应的是上面的ApiResource的key
                    /*
                     * (这里假设为是VIP卡片,一个资源一张卡片,每个卡片对应的我上面的资源的key,
                     * 所以,
                     * 1.哪怕你有卡片,但是我这个资源不开放或者没有对应的资源,你也是访问不到的,即401
                     * 2.哪怕我有资源,你前面的身高体重都符合,口令也正确,但是你没有VIP卡片,你也是无法访问的)
                     */
                    AllowedScopes = {"api1", "api2"}
                }
            };
        }

        /// <summary>
        /// 加密   CreateDate:2019-12-26 11:19:04;Author:Ling_bug
        /// </summary>
        /// <param name="valueString"></param>
        /// <returns></returns>
        private static string Encrypt(string valueString)
        {
            return string.IsNullOrWhiteSpace(valueString) ? null : valueString.Sha256();
        }
    }
}

3.startup配置:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace IdentityServerSolution
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddIdentityServer()//配置id4(跟物业说我现在需要给顾客分配钥匙)
                .AddInMemoryApiResources(Config.GetApiResources())//配置允许请求的api(告诉物业我家里的哪些东西可以让顾客使用)
                .AddInMemoryClients(Config.GetClients())//配置允许哪些client请求(告诉物业满足什么条件的顾客才可以拿到我家的钥匙)
                .AddDeveloperSigningCredential();

            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            //启用id4,将id4中间件添加到管道中(跟物业说一下,身份符合要求的才可以发送钥匙)
            app.UseIdentityServer();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvc();
        }
    }
}

4.此时已经identityServer4服务端创建完毕了,我们可以运行起来

a.访问http://localhost:3065/.well-known/openid-configuration,可以看到identityServer4的配置,可以不用管,知道就可以

b.在项目根目录会多一个tempkey.rsa文件,这个也不用管

c.使用postman,获取到你心心念念的token


二、创建WebApi(项目中客户端真实需要请求的服务)(IdentityApi)

1.startup配置:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace IdentityApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            //配置身份认证(告诉物业任何进来的顾客都需要身份验证,看看钥匙对不对)
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
                {
                    //身份认证平台地址(身份认证时会去这个地址验证token是否有效)(告诉物业去哪里验证客户的钥匙是否正确)
                    options.Authority = "http://localhost:3065";
                    //一般默认(true),开发环境时可以设置为false
                    options.RequireHttpsMetadata = false;
                    //apiResource(这里目前还还不知道如何配置多个)
                    //(钥匙正确,进入要使用啥的顾客才可以放行,其他的不允许,这里就是进去要使用api1的放行,其他的钥匙正确也不让你进)
                    options.Audience = "api1";
                });
            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            //启用身份认证中间件(告诉物业只认钥匙不认人)
            app.UseAuthentication();
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseMvc();
        }
    }
}

2.创建服务服务器,获取当前用户信息:

using System.Linq;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace IdentityApi.Controllers
{
    [Authorize]//Authorize特性启用身份认证
    [Route("Identity")]
    public class IdentityController : ControllerBase
    {
        /// <summary>
        /// 获取到当前用户的身份信息   CreateDate:2019-12-26 11:25:05;Author:Ling_bug
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IActionResult Get()
        {
            var data = User.Claims.Select(r => new { r.Type, r.Value });
            return new JsonResult(data);
        }
    }
}


三、控制台应用程序(用来模拟客户端发送请求)(IdentityModelClient)

using IdentityModel.Client;
using Newtonsoft.Json.Linq;
using System;
using System.Net.Http;

namespace IdentityModelClient
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                TestIdentity4Async();
            }
            catch (Exception e)
            {
                Console.WriteLine("异常:" + e.Message);
            }
            Console.ReadKey();
        }

        private static async void TestIdentity4Async()
        {
            //获取到获取token的url
            var client = new HttpClient();
            var disco = await client.GetDiscoveryDocumentAsync("http://localhost:3065");
            if (disco.IsError)
            {
                Console.WriteLine("获取到获取token的url失败:" + disco.Error);
                return;
            }
            Console.WriteLine("获取token的url为:" + disco.TokenEndpoint);
            Console.WriteLine();

            //获取token
            var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
            {
                Address = disco.TokenEndpoint,//就是我们postman请求token的地址
                ClientId = "Client",//客户端
                ClientSecret = "secret",//秘钥
                Scope = "api1"//请求的api
            });
            if (tokenResponse.IsError)
            {
                Console.WriteLine("获取token失败:" + tokenResponse.Error);
                return;
            }
            Console.WriteLine("获取token的response:");
            int index = 0;
            foreach (var proc in tokenResponse.GetType().GetProperties())
            {
                Console.WriteLine($"{++index}.{proc.Name}:{proc.GetValue(tokenResponse)}");
            }
            Console.WriteLine();

            //模拟客户端调用需要身份认证的api
            var apiClient = new HttpClient();
            //赋值token(携带token访问)
            apiClient.SetBearerToken(tokenResponse.AccessToken);
            //发起请求
            var response = await apiClient.GetAsync("http://localhost:10469/Identity");
            if (response.IsSuccessStatusCode)
            {
                //请求成功
                var content = await response.Content.ReadAsStringAsync();
                Console.WriteLine("请求成功,返回结果是:" + JArray.Parse(content));
            }
            else
            {
                //请求失败
                Console.WriteLine($"请求失败,状态码为:{(int)response.StatusCode},描述:{response.StatusCode.ToString()}");
            }
        }
    }
}

运行起来,结果为:

 

Ending~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值