• IdentityServer4与API单项目整合(net core 3.X)


    一、创建一个空的api项目

    添加identityserver4的nuget包

     配置config文件

    public static IEnumerable<IdentityResource> GetIdentityResources()
            {
                return new IdentityResource[]
                {
                    new IdentityResources.OpenId(),
                    new IdentityResources.Profile(),
                };
            }
            /// <summary>
            /// API信息
            /// </summary>
            /// <returns></returns>
            public static IEnumerable<ApiResource> GetApis()
            {
                return new[]
                {
                    new ApiResource(IdentityServerConstants.LocalApi.ScopeName),
                    new ApiResource("manageApi", "Demo API with Swagger")
                };
            }
            /// <summary>
            /// 客服端信息
            /// </summary>
            /// <returns></returns>
            public static IEnumerable<Client> GetClients()
            {
                return new[]
                {
                    new Client
                    {
                        ClientId = "clientId",//客服端名称
                        ClientName = "Swagger UI for demo_api",//描述
                        AllowedGrantTypes = GrantTypes.ResourceOwnerPassword ,//指定允许的授权类型(AuthorizationCode,Implicit,Hybrid,ResourceOwner,ClientCredentials的合法组合)。
                        AllowAccessTokensViaBrowser = true,//是否通过浏览器为此客户端传输访问令牌
                        AccessTokenLifetime = 3600*24,
                        AuthorizationCodeLifetime=3600*24,
                        ClientSecrets ={new Secret("secret".Sha256())},
                        //RedirectUris =
                        //{
                        //    "http://localhost:59152/oauth2-redirect.html"
                        //},
                        AllowedCorsOrigins = new string[]{ "http://localhost:9012", "http://101.133.234.110:21004",  "http://115.159.83.179:21004" },
                        AllowedScopes = { "manageApi", IdentityServerConstants.LocalApi.ScopeName }//指定客户端请求的api作用域。 如果为空,则客户端无法访问
                    }
                };
            }

    在Startup.cs中注入IdentityServer服务并使用中间件

     //配置身份服务器与内存中的存储,密钥,客户端和资源
                services.AddIdentityServer()
                       .AddDeveloperSigningCredential()
                       .AddInMemoryApiResources(config.GetApis())//添加api资源
                       .AddInMemoryClients(config.GetClients())//添加客户端
                       .AddInMemoryIdentityResources(config.GetIdentityResources())//添加对OpenID Connect的支持
                         //使用自定义验证
                        .AddResourceOwnerValidator<CustomResourceOwnerPasswordValidator>()
                        .AddProfileService<ProfileService>();
    //启用IdentityServer
                app.UseIdentityServer();

    接下来,我们去实现CustomResourceOwnerPasswordValidator这个类

    创建一个CustomResourceOwnerPasswordValidator类,继承IResourceOwnerPasswordValidator

     public class CustomResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
        {
            public Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
            {
                throw new NotImplementedException();
            }
        }

    接下来,我们就是些验证了

    我们创建一个服务,去获取数据库里面的用户,验证是否有当前登录的用户

    这里我们创建了一个userservice来验证我们的输入用户是否存在

      public class UserService : IUserService
        {
            public async Task<TestPhoneUser> ValidateCredentials(string nameorphone, string password)
            {
                var dto= TestUser.FirstOrDefault(c => c.Phone == nameorphone && password == c.PassWord);
                if (dto != null)
                    return dto;
                else
                    return null;
            }
            public class TestPhoneUser
            {
                /// <summary>
                /// 唯一标识
                /// </summary>
                public int Id { get; set; }
                /// <summary>
                /// 手机号
                /// </summary>
                public string Phone { get; set; }
                /// <summary>
                /// 密码
                /// </summary>
                public string PassWord { get; set; }
            }
            public List<TestPhoneUser> TestUser = new List<TestPhoneUser>
            {
                new TestPhoneUser
                {
                    Id=1,
                    Phone="12345678911",
                    PassWord="123qwe"
                },new TestPhoneUser
                {
                    Id=2,
                    Phone="123",
                    PassWord="123qwe"
                }
            };
            
        }

    现在,我们去完善CustomResourceOwnerPasswordValidator

    public class CustomResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
        {
            private readonly IUserService _userService;
    
            public CustomResourceOwnerPasswordValidator(IUserService userService)
            {
                _userService = userService;
            }
            public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
            {
                var dto = await _userService.ValidateCredentials(context.UserName, context.Password);
                if (dto!=null)
                {
                    context.Result = new GrantValidationResult(
                       dto.Id.ToString(),
                       "pwd",
                       DateTime.Now);
                }
                else
                {
                    //验证失败
                    context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "用户名密码错误");
                }
            }
        }

     再要配置profile

     public class ProfileService:IProfileService
        {
            public Task GetProfileDataAsync(ProfileDataRequestContext context)
            {
                context.IssuedClaims = context.Subject.Claims.ToList();
                return Task.CompletedTask;
            }
    
            public Task IsActiveAsync(IsActiveContext context)
            {
                context.IsActive = true;
    
                return Task.CompletedTask;
            }
        }

    注入刚刚添加的服务

     services.AddScoped<IUserService, UserService>();
     services.AddScoped<IProfileService, ProfileService>();

    在Startup.cs中加入identityServer验证

     //用户校验
                services.AddLocalApiAuthentication();
    
                services.AddAuthorization(options =>
                {
                    options.AddPolicy(IdentityServerConstants.LocalApi.PolicyName, policy =>
                    {
                        policy.AddAuthenticationSchemes(IdentityServerConstants.LocalApi.AuthenticationScheme);
                        policy.RequireAuthenticatedUser();
                    });
                });
                app.UseAuthentication();

    postman测试

     反复验证了很多遍,都没有问题(因为我之前core2.x的时候就是这样写的)

    最后去identityserver官网,找到了问题所在

    现在的资源都换成了apiscope

    然后,我把ApiResource都换成了ApiScope然后再运行

    ok,完美!!!(这个坑,坑了我一下午)

    最后再给api添加验证就行了

    [Authorize(LocalApi.PolicyName)]

    访问api

    访问成功

    参考文献:https://identityserver4.readthedocs.io/en/latest/quickstarts/1_client_credentials.html#defining-an-api-scope

     github:https://github.com/LGXQWER/SingleProjectDemo

  • 相关阅读:
    第7章例7-12
    第7章例7-11
    第7章例7-9
    第7章例7-8
    第7章例7-7
    第7章例7-6
    第7章例7-5
    第7章例7-4
    第7章例7-3
    第7章例7-2
  • 原文地址:https://www.cnblogs.com/liguix/p/13704779.html
Copyright © 2020-2023  润新知