1、NuGet 引用
   Microsoft.AspNetCore.Authentication.OAuth
   IdentityServer4

2、资源配置(Config.cs)

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

namespace OAuth2IdentityServer.OAuth2
{
    public class Config
    {
        public static IEnumerable<IdentityResource> GetIdentityResourceResources()
        {
            return new List<IdentityResource>
            {
                new IdentityResources.OpenId(), //必须要添加,否则报无效的scope错误
                new IdentityResources.Profile(),
                new IdentityResources.Email(),
                new IdentityResource
                {
                    Name = "role",
                    UserClaims = new List<string> {"role"}
                }
            };
        }

        public static IEnumerable<Scope> GetScopes()
        {
            return new List<Scope>
            {
                new Scope
                {
                    Name = "api1",
                    Description = "My API",
                },
                //如果想带有RefreshToken,那么必须设置:StandardScopes.OfflineAccess
                //StandardScopes.OfflineAccess,
            };
        }

        public static IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>
            {
                new ApiResource("clientservice", "CAS Client Service"),
                new ApiResource("agentservice", "CAS Agent Service"),
                new ApiResource("productservice", "CAS Product Service")
                {
                    ApiSecrets = { new Secret("api1pwd".Sha256()) }
                },
                new ApiResource
                {
                    Name = "customAPI",
                    DisplayName = "Custom API",
                    Description = "Custom API Access",
                    UserClaims = new List<string> {"role"},
                    ApiSecrets = new List<Secret> {new Secret("scopeSecret".Sha256())},
                    Scopes = new List<Scope>
                    {
                        new Scope("customAPI.read"),
                        new Scope("customAPI.write")
                    }
                }
            };
        }

        public static IEnumerable<ApiResource> GetResources()
        {
            return new List<ApiResource>
            {
                new ApiResource { Name = "ImageResource", Scopes ={ new Scope ("ImageResource") }},//Scopes必须配置,否则获取token时返回 invalid_scope                
                new ApiResource { Name = "FileResourse" },
                new ApiResource { Name ="Api", Scopes = { new Scope ("Api") }}
            };
        }

        /// <summary>
        /// Define which uses will use this IdentityServer
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<TestUser> GetUsers()
        {
            return new[]
            {
                new TestUser
                {
                    SubjectId = "10001",
                    Username = "[email protected]",
                    Password = "edisonpassword"
                },
                new TestUser
                {
                    SubjectId = "10002",
                    Username = "[email protected]",
                    Password = "andypassword"
                },
                new TestUser
                {
                    SubjectId = "10003",
                    Username = "[email protected]",
                    Password = "leopassword"
                },
                new TestUser
                {
                    SubjectId = "5BE86359-073C-434B-AD2D-A3932222DABE",
                    Username = "scott",
                    Password = "password",
                    Claims = new List<Claim>
                    {
                        new Claim(JwtClaimTypes.Email, "[email protected]"),
                        new Claim(JwtClaimTypes.Role, "admin")
                    }
                }
            };
        }
    }
}

3、资源配置(Clients.cs)

using IdentityServer4;
using IdentityServer4.Models;
using IdentityServer4.Stores;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace OAuth2IdentityServer.OAuth2
{
    public class Clients
    {
        /// <summary>
        /// 授权模式:客户端模式 GrantTypes.ClientCredentials
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>
            {
                //client credentials client(OK)
                new Client
                {
                    ClientId = "ClientIdOK",
                    AllowedGrantTypes = GrantTypes.ClientCredentials,//授权模式:客户端模式
                    AllowedScopes = { "ImageResource","Api" }, //允许访问的资源 GetResources()中配置的
                    ClientSecrets = { new Secret { Value= "ClientSecret".Sha256(), Expiration = DateTime.Now.AddMinutes(5)} }
                },
                //client credentials client(OK)
                new Client
                {
                    ClientId = "client1",
                    ClientName = "Example Client Credentials Client Application",
                    AllowedGrantTypes = GrantTypes.ClientCredentials,//授权模式:客户端模式
                    AllowedScopes = //对应的是 “OAuth2.Config.GetApiResources()” 或 “OAuth2.Config.GetResources()”中的资源
                    {
                        "ImageResource", "Api",
                        //IdentityServerConstants.StandardScopes.OpenId, //加上此参数报错
                        //IdentityServerConstants.StandardScopes.Profile,//加上此参数报错
                        //IdentityServerConstants.StandardScopes.OfflineAccess,//加上此参数报错
                    },
                    ClientSecrets = { new Secret("181a7853053b4be9b0ac9d9c709f3ecd".Sha256()) },
                    AllowedCorsOrigins = new List<string> { "http://localhost:44389" },
                    RedirectUris = { "http://localhost:6321/Home/AuthCode" },
                    PostLogoutRedirectUris = { "http://localhost:44389/" },
                    AccessTokenLifetime = 3600, //AccessToken过期时间, in seconds (defaults to 3600 seconds / 1 hour)
                    AuthorizationCodeLifetime = 300,  //设置AuthorizationCode的有效时间,in seconds (defaults to 300 seconds / 5 minutes)
                    AbsoluteRefreshTokenLifetime = 2592000,  //RefreshToken的最大过期时间,in seconds. Defaults to 2592000 seconds / 30 day
                },
                // resource owner password grant client
                new Client
                {
                    ClientId = "client2",
                    ClientName = "Example Client Credentials Client Application",
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
                    ClientSecrets = { new Secret("ClientSecret".Sha256()) },
                    AllowedCorsOrigins = new List<string> { "http://localhost:44389" },
                    AllowedScopes = { "ImageResource", "Api" },
                    RedirectUris = { "http://localhost:6321/Home/AuthCode" },
                    PostLogoutRedirectUris = { "http://localhost:6321/" },
                    AccessTokenLifetime = 3600, //AccessToken过期时间, in seconds (defaults to 3600 seconds / 1 hour)
                    AuthorizationCodeLifetime = 300,  //设置AuthorizationCode的有效时间,in seconds (defaults to 300 seconds / 5 minutes)
                    AbsoluteRefreshTokenLifetime = 2592000,  //RefreshToken的最大过期时间,in seconds. Defaults to 2592000 seconds / 30 day
                },
                //Implicit
                new Client
                {
                    ClientId = "openIdConnectClient",
                    ClientName = "Example Implicit Client Application",
                    AllowedGrantTypes = GrantTypes.Implicit,
                    AllowedScopes = new List<string>
                    {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
                        IdentityServerConstants.StandardScopes.Email,
                        "role",
                        "customAPI.write"
                    },
                    RedirectUris = new List<string> {"https://localhost:44330/signin-oidc"},
                    PostLogoutRedirectUris = new List<string> {"https://localhost:44330"},
                    AccessTokenLifetime = 3600, //AccessToken过期时间, in seconds (defaults to 3600 seconds / 1 hour)
                    AuthorizationCodeLifetime = 300,  //设置AuthorizationCode的有效时间,in seconds (defaults to 300 seconds / 5 minutes)
                    AbsoluteRefreshTokenLifetime = 2592000,  //RefreshToken的最大过期时间,in seconds. Defaults to 2592000 seconds / 30 day
                }
            };
        }

        public static IEnumerable<Client> GetClientsTest()
        {
            return new List<Client>
            {
                new Client
                {
                    ClientId = "ClientId",
                    AllowedGrantTypes = GrantTypes.ClientCredentials,//授权模式:客户端模式
                    AllowedScopes ={ "ImageResource","Api" }, //允许访问的资源 GetResources()中配置的
                    ClientSecrets ={ new Secret { Value= "ClientSecret".Sha256(), Expiration=DateTime.Now.AddMinutes(5)} }
                }
            };
        }
    }
}

4、ResourceOwnerPasswordValidator.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using IdentityModel;
using IdentityServer4.Models;
using IdentityServer4.Validation;

namespace OAuth2IdentityServer.OAuth2
{
    public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
    {
        public ResourceOwnerPasswordValidator()
        {
        }

        public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
        {
            //根据context.UserName和context.Password与数据库的数据做校验,判断是否合法
            if (context.UserName == "wjk" && context.Password == "123")
            {
                context.Result = new GrantValidationResult(
                 subject: context.UserName,
                 authenticationMethod: "custom",
                 claims: GetUserClaims());
            }
            else
            {
                //验证失败
                context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "invalid custom credential");
            }
        }

        //可以根据需要设置相应的Claim
        private Claim[] GetUserClaims()
        {
            return new Claim[]
            {
                new Claim("UserId", 1.ToString()),
                new Claim(JwtClaimTypes.Name,"wjk"),
                new Claim(JwtClaimTypes.GivenName, "jaycewu"),
                new Claim(JwtClaimTypes.FamilyName, "yyy"),
                new Claim(JwtClaimTypes.Email, "[email protected]"),
                new Claim(JwtClaimTypes.Role,"admin")
            };
        }
    }
}

5、ProfileService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using IdentityServer4.Models;
using IdentityServer4.Services;

namespace OAuth2IdentityServer.OAuth2
{
    public class ProfileService : IProfileService
    {
        public async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            try
            {
                //depending on the scope accessing the user data.
                var claims = context.Subject.Claims.ToList();

                //set issued claims to return
                context.IssuedClaims = claims.ToList();
            }
            catch (Exception ex)
            {
                //log your error
            }
        }

        public async Task IsActiveAsync(IsActiveContext context)
        {
            context.IsActive = true;
        }
    }
}

6、Startup.cs(“认证服务器”配置 IdentityServer,颁发 token)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using OAuth2IdentityServer.OAuth2;

namespace OAuth2IdentityServer
{
    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.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            #region 对应 grant_type = Client_Credentials 模式(测试通过 - OK)

            //services.AddIdentityServer()
            //    .AddDeveloperSigningCredential()
            //    .AddInMemoryApiResources(Config.GetResources())
            //    .AddInMemoryClients(Clients.GetClients());

            #endregion

            #region 对应 grant_type = Resource_Owner_Password 模式(测试通过 - OK)

            //services.AddIdentityServer()
            //    .AddDeveloperSigningCredential()
            //    .AddInMemoryApiResources(Config.GetResources())
            //    .AddInMemoryClients(Clients.GetClients())
            //    .AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()
            //    .AddProfileService<ProfileService>();

            #endregion

            #region 同时兼容 Client_Credentials 和 Resource_Owner_Password 模式(测试通过 - OK)
            services.AddIdentityServer()
                .AddDeveloperSigningCredential()
                .AddInMemoryApiResources(Config.GetResources())
                .AddInMemoryClients(Clients.GetClients())
                .AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()
                .AddProfileService<ProfileService>();
            #endregion

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment 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.UseCookiePolicy();

            app.UseIdentityServer();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

7、Program.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace OAuth2IdentityServer
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }
}

8、启动项目之后,浏览器输入 https://localhost:44305/.well-known/openid-configuration 查看文档(端口号以项目运行的真实地址为准)

9、获取token(Client Credentials 模式)

.NET Core OAuth IdentityServer4 Token

.NET Core OAuth IdentityServer4 Token

10、获取token(Resource Owner Password 模式)

.NET Core OAuth IdentityServer4 Token

.NET Core OAuth IdentityServer4 Token

*、资源服务器,Startup.cs 配置如下:

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

namespace ImageResourceApi
{
    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.AddAuthentication(config =>
            {
                config.DefaultScheme = "Bearer";
            }).AddIdentityServerAuthentication(option =>
            {
                option.Authority = "https://localhost:44308"; //认证服务的url
                option.ApiName = "ImageResource";
                option.ApiSecret = "ClientSecret".ToSha256();// 访问的secret
                option.SaveToken = true;
                option.RequireHttpsMetadata = false;
            });
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // 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.UseAuthentication();

            app.UseMvc();
        }
    }
}

*、资源服务器:在需要进行授权验证的资源接口(controller控制器或方法)上设置AuthorizeAttribute:

using System.Collections.Generic;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace ImageResourceApi.Controllers
{
    [Authorize]
    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
        // GET api/values
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        [HttpGet("{id}")]
        public ActionResult<string> Get(int id)
        {
            return "value";
        }

        // POST api/values
        [HttpPost]
        public void Post([FromBody] string value)
        {
        }

        // PUT api/values/5
        [HttpPut("{id}")]
        public void Put(int id, [FromBody] string value)
        {
        }

        // DELETE api/values/5
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
        }
    }
}

*、客户端 发送web请求 资源服务器,PostMan方式如下:

.NET Core OAuth IdentityServer4 Token

.NET Core OAuth IdentityServer4 Token

【注意:】“认证服务器”中\OAuth2\Clients.cs =>AllowedScopes  要和 “资源服务器” Startup.cs => option.ApiName 的值相匹配

*、

*、

*、

 

相关文章:

  • 2022-12-23
  • 2018-05-07
  • 2022-12-23
  • 2019-10-26
  • 2022-12-23
  • 2021-12-08
猜你喜欢
  • 2022-12-23
  • 2021-06-25
  • 2021-10-27
  • 2022-12-23
  • 2021-10-26
  • 2019-10-24
  • 2021-05-21
相关资源
相似解决方案