dotnet core微服務框架Jimu ~ 會員授權微服務

Flamesky發表於2024-10-30

提供授權服務,使用者使用會員的使用者名稱和密碼獲取 token, 帶著 token 訪問受保護的介面,如瀏覽和釋出新聞。

有 2 個公開的 api:

  1. token: 獲取 token;
  2. GetCurrentMemberInfo: 獲取當前 token 的會員資訊;

有 1 個不公開的方法:

  1. GetMemberInfo:根據會員使用者名稱和密碼,獲取會員資訊,該方法供獲取 token 的 api 呼叫;

1 宣告介面,建立基於 .Net Core 6.0 的類庫專案,命名為 Auth.IServices

1.1 新增 jimu 引用

Install-Package  Jimu

1.2 建立 dto 類

using System;
using System.Collections.Generic;
using System.Text;

namespace Auth.IServices
{
    public class MemberInfo
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public string NickName { get; set; }
        public string Role { get; set; }

    }
}

1.3 宣告公開的微服務介面

using System;
using System.Collections.Generic;
using System.Text;
using Jimu;

namespace Auth.IServices
{
    public interface IAuthMemberService : IJimuService
    {
        MemberInfo GetMemberInfo(string username, string password);
    }
}

上面的介面只繼承 IJimuService, 不宣告訪問路由和介面屬性,因為它不公開給外部呼叫的,但要用 autofac 註冊到系統,在生成 token 時呼叫,所以需要繼承 IJimuService。

using System;
using System.Threading.Tasks;
using Jimu;

namespace Auth.IServices
{
    [JimuServiceRoute("/api/v1/member")]
    public interface IMemberService : IJimuService
    {
        [JimuService(EnableAuthorization = true, CreatedBy = "grissom", CreatedDate = "2018-07-17", Comment = "get current token member info")]
        MemberInfo GetCurrentMemberInfo();
    }
}

上面的介面宣告瞭 EnableAuthorization = true,需要授權的使用者才能訪問(即請求時要帶上 token),該方法是獲取當前會員資訊。

2 實現介面,建立基於 .Net Core 6.0 的類庫專案,命名為 Auth.Services

2.1 新增對介面專案 Auth.IServices 的引用

2.2 實現介面

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Auth.IServices;
using Jimu;

namespace Auth.Services
{
    public class AuthMemberService : IAuthMemberService
    {
        static List<MemberInfo> _membersDb = new List<MemberInfo>();
        readonly ILogger _logger;
        public AuthMemberService(ILogger logger)
        {
            _logger = logger;
        }

        static AuthMemberService()
        {
            // mock some member 
            _membersDb.Add(new MemberInfo { Id = Guid.NewGuid().ToString(), Name = "grissom", NickName = "Gil", Role = "admin" });
            _membersDb.Add(new MemberInfo { Id = Guid.NewGuid().ToString(), Name = "foo", NickName = "Fo", Role = "guest" });
        }

        public MemberInfo GetMemberInfo(string username, string password)
        {
            var member = _membersDb.FirstOrDefault(x => x.Name == username && "123" == password);

            _logger.Debug($"username: {username}, found {(member == null ? "no " : "")} member.");

            return member;
        }
    }
}

logger 是透過依賴注入的

using Jimu;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Auth.IServices
{
    public class MemberService : IMemberService
    {
        readonly ILogger _logger;
        readonly JimuPayload _jimuPayload;
        public MemberService(ILogger logger, JimuPayload jimuPayload)
        {
            _logger = logger;
            _jimuPayload = jimuPayload;
        }

        public MemberInfo GetCurrentMemberInfo()
        {
            _logger.Debug($"current token member username: {_jimuPayload.Items["username"]}");

            return Newtonsoft.Json.JsonConvert.DeserializeObject<MemberInfo>(_jimuPayload.Items["member"].ToString());
        }


    }
}

logger 和 jimuPayload 都是透過依賴注入的。JimuPayload 是 Jimu 框架解析 token 獲取的一些生成 token 時,新增的資訊(參考下面生成 token 的方法)。如果請求的 token 無效,則 JimuPayload 為 null。

3 微服務的宿主伺服器,建立基於 .Net Core 2.0 的控制檯應用, 命名為 Auth.Server

3.1 新增對專案: Auth.Services 的引用

3.2 新增 jimu.server 和 Jimu.Common.Discovery.ConsulIntegration 引用

Install-Package  Jimu.Server
Install-Package  Jimu.Common.Discovery.ConsulIntegration

3.3 啟動 jimu 服務和生成 token 的程式碼

using System;
using Autofac;
using Jimu;
using Jimu.Server;
using Jimu.Server.OAuth;
using Auth.IServices;

namespace Auth.Server
{
    class Program
    {
        static void Main(string[] args)
        {
            IServiceHost host = null;

            var builder = new ServiceHostServerBuilder(new ContainerBuilder())
             .UseLog4netLogger()
             .LoadServices("Auth.IServices", "Auth.Services")
             .UseDotNettyForTransfer("127.0.0.1", 8000)
             .UseConsulForDiscovery("127.0.0.1", 8500, "JimuService", $"127.0.0.1:8000")
             .UseJoseJwtForOAuth<DotNettyAddress>(new JwtAuthorizationOptions
             {
                 SecretKey = "123456", // 生成 token 的金鑰
                 ExpireTimeSpan = new TimeSpan(3, 0, 0, 0), // token 有效時間 3 天
                 ValidateLifetime = true, // 是否啟動驗證 token 的有效時間
                 ServerIp = "127.0.0.1", // 生成 token 的宿主伺服器地址
                 ServerPort = 8000, // 生成 token 的宿主伺服器埠
                 TokenEndpointPath = "api/oauth/token?username=&password=", // 獲取 token 的路由,注意字尾 ?username=&password= 是固定的
                 CheckCredential = new Action<JwtAuthorizationContext>(ctx =>
                 {
                     var memberService = host.Container.Resolve<IAuthMemberService>();

                     var member = memberService.GetMemberInfo(ctx.UserName, ctx.Password);
                     if (member == null)
                     {
                         ctx.Rejected("username or password is incorrect.", "");
                     }
                     else
                     {
                         // 上面提到的 JimuPayload 就是包含這些資料
                         ctx.AddClaim("roles", member.Role); // 新增角色到 token
                         ctx.AddClaim("member", Newtonsoft.Json.JsonConvert.SerializeObject(member)); // 把整個 member 序列化打包到 token

                     }
                 }), // 生成 token 的配置項和驗證邏輯
             });
            using (host = builder.Build())
            {
                host.Run();
                while (true)
                {
                    Console.ReadKey();
                }
            }
        }
    }
}

相關文章