ASP.NET Core 項目簡單實現身份驗證及鑒權

来源:https://www.cnblogs.com/wiseant/archive/2019/03/12/10515842.html
-Advertisement-
Play Games

ASP.NET Core 身份驗證及鑒權 目錄 + 項目準備 + 身份驗證 定義基本類型和介面 編寫驗證處理器 實現用戶身份驗證 + 許可權鑒定 思路 編寫過濾器類及相關介面 實現屬性註入 實現用戶許可權鑒定 + 測試 環境 + VS 2017 + ASP.NET Core 2.2 目標 以相對簡單優雅 ...


ASP.NET Core 身份驗證及鑒權

目錄

環境

  • VS 2017
  • ASP.NET Core 2.2

目標

  以相對簡單優雅的方式實現用戶身份驗證和鑒權,解決以下兩個問題:

  • 無狀態的身份驗證服務,使用請求頭附加訪問令牌,幾乎適用於手機、網頁、桌面應用等所有客戶端
  • 基於功能點的許可權訪問控制,可以將任意功能點許可權集合授予用戶或角色,無需硬編碼角色許可權,非常靈活

項目準備

  1. 創建一個ASP.NET Core Web應用程式

    • 使用ASP.NET Core 2.2
    • 模板選[空]
    • 不啟用HTTPS
    • 不進行身份驗證
  2. 通過NuGet安裝Swashbuckle.AspNetCore程式包,併在Startup類中啟用Swagger支持

    因為這個示例項目不打算編寫前端網頁,所以直接使用Swagger來調試,真的很方便。

  3. 添加一個空的MVC控制器(HomeController)和一個空的API控制器(AuthController)

    HomeController.Index()方法中只寫一句簡單的跳轉代碼即可:

    return new RedirectResult("~/swagger");

    AuthController類中隨便寫一兩個骨架方法,方便看效果。

  4. 運行項目,會自動打開瀏覽器並跳轉到Swagger頁面。

身份驗證

定義基本類型和介面

  1. ClaimTypes 定義一些常用的聲明類型常量

  2. IClaimsSession 表示當前會話信息的介面

  3. ClaimsSession 會話信息實現類
    根據聲明類型從ClaimsPrincipal.ClaimsIdentity屬性中讀取用戶ID、用戶名等信息。

    實際項目中可從此類繼承或完全重新實現自己的Session類,以添加更多的會話信息(例如工作部門)

  4. IToken 登錄令牌介面
    包含訪問令牌、刷新令牌、令牌時效等令牌

  5. IIdentity 身份證明介面
    包含用戶基本信息及令牌信息

  6. IAuthenticationService 驗證服務介面
    抽象出來的驗證服務介面,僅規定了四個身份驗證相關的方法,如需擴展可定義由此介面派生的介面。

    方法名 返回值類型 說明
    Login(userName, password) IIdentity 根據用戶名及密碼驗證其身份,成功則返回身份證明
    Logout() void 註銷本次登錄,即使未登錄也不報錯
    RefreshToken(refreshToken) Token 刷新登錄令牌,如果當前用戶未登錄則報錯
    ValidateToken(accessToken) IIdentity 驗證訪問令牌,成功則返回身份證明
  7. SimpleToken 登錄令牌的簡化實現

    這個類提不提供都可以,實際項目中大家生成Token的演算法肯定是各不相同的,提供簡單實現僅用於演示

編寫驗證處理器

  1. BearerDefaults 定義了一些與身份驗證相關的常量

    如:AuthenticationScheme

  2. BearerOptions 身份驗證選項類

    AuthenticationSchemeOptions繼承而來

  3. BearerValidatedContext 驗證結果上下文

  4. BearerHandler 身份驗證處理器 <= 關鍵類

    覆蓋了HandleAuthenticateAsync()方法,實現自定義的身份驗證邏輯,簡述如下:

    1. 獲取訪問令牌。從請求頭中獲取authorization信息,如果沒有則從請求的參數中獲取

    2. 如果訪問令牌為空,則終止驗證,但不報錯,直接返回AuthenticateResult.NoResult()

    3. 調用從構造函數註入的IAuthenticationService實例的ValidateToken()方法,驗證訪問令牌是否有效,如果該方法觸發異常(例如令牌過期)則捕獲後通過AuthenticateResult.Fail()返回錯誤信息,如果該方法返回值為空(例如訪問令牌根本不存在)則返回AuthenticateResult.NoResult(),不報錯。

    4. 到這一步說明身份驗證已經通過,而且拿到身份證明信息,根據該信息創建Claim數組,然後再創建一個包含這些Claim數據的ClaimsPrincipal實例,並將Thread.CurrentPrincipal設置為該實例。

      重點:其實,HttpContext.User屬性的類型正是CurrentPrincipal,而其值應該就是來自於Thread.CurrentPrincipal

    5. 構造BearerValidatedContext實例,並將其Principal屬性賦值為上面創建的ClaimsPrincipal實例,然後調用Success()方法,表示驗證成功。最後返回該實例的Result屬性值。

  5. BearerExtensions 包含一些擴展方法,提供使用便利

    重點在於AddBearer()方法內調用builder.AddScheme<TOptions,THandler>()泛型方法時,分別使用了前面編寫的BearerOptionsBearerHandler類作為泛型參數。

    public static AuthenticationBuilder AddBearer(...)
    {
        return builder.AddScheme<BearerOptions, BearerHandler>(...);
    }

    如果想要自己實現BearerHandler類的驗證邏輯,可以拋棄此類,重新編寫使用新Handler類的擴展方法

實現用戶身份驗證

說明

  這部分是身份驗證的落地,實際項目中應該將上面兩步(定義基本類型和介面、編寫驗證處理器)的代碼抽象出來,成為獨立可復用的軟體包,利用該軟體包進行身份驗證的實現邏輯可參照此示例代碼。

實現步驟

  1. Identity 身份證明實現類

  2. SampleAuthenticationService 驗證服務的簡單實現

    出於演示方便,固化了三個用戶(admin/123456、user/123、tester/123)

  3. AuthController 通過HTTP向前端提供驗證服務的控制器類

    提供了用戶登錄、令牌刷新、令牌驗證等方法。

  4. 還需要修改項目中Startup.cs文件,添加依賴註入規則、身份驗證,並啟用身份驗證中間件。
    ConfigureServices方法內添加代碼:

    //添加依賴註入規則
    services.AddScoped<IClaimsSession, ClaimsSession>();
    services.AddScoped<IAuthenticationService, SampleAuthenticationService>();
    //添加身份驗證
    services.AddAuthentication(options =>
    {
     options.DefaultAuthenticateScheme = BearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = BearerDefaults.AuthenticationScheme;
    }).AddBearer();

    Configure()方法內添加代碼:

    //啟用身份驗證中間件
    app.UseAuthentication();

通過Swagger測試

  • 測試登錄功能

    啟動項目,自動進入[Swagger UI]界面,點擊/api/Auth/Login方法,不修改輸入框中的內容直接點擊[Execute]按鈕,可以見到返回401錯誤碼。

    在輸入框中輸入{"userName": "admin", "password": "123456"},然後點擊[Execute]按鈕,系統驗證成功並返回身份證明信息。

記下訪問令牌2ad43df2c11d48a18a88441adbf4994a和刷新令牌9bbaf811ed8b4d29b638777d4f89238e

  • 測試刷新登錄令牌

    點擊/api/Auth/Refresh方法,在輸入框中輸入上面獲取到的刷新令牌9bbaf811ed8b4d29b638777d4f89238e,然後點擊[Execute]按鈕,返回401錯誤碼。原因是因為我們並未提供訪問令牌。

    點擊方法名右側的[鎖]圖標,在彈出框中輸入之前獲取的訪問令牌2ad43df2c11d48a18a88441adbf4994a並點擊[Authorize]按鈕後關閉對話框,重新點擊[Execute]按鈕,成功獲取到新的登錄令牌。

  • 測試驗證訪問令牌

    點擊/api/Auth/Validate方法,在輸入框中輸入第一次獲取的到訪問令牌2ad43df2c11d48a18a88441adbf4994a,然後點擊[Execute]按鈕,返回400錯誤碼,表明發起的請求參數有誤。因為此方法是支持匿名訪問的,所以錯誤碼不會是401.

    將輸入框內容修改為新的訪問令牌f37542e162ed4855921ddf26b05c3f25,然後點擊[Execute]按鈕,驗證成功,返回了對應的用戶身份證明信息。

許可權鑒定

  在ASP.NET Core項目中實現基於角色的授權很容易,在一些許可權管理並不複雜的項目中,採取這種方式來實現許可權鑒定簡單可行。有興趣可以參考這篇博文ASP.NET Core 認證與授權5:初識授權
  但是,對於稍微複雜一些的項目,許可權劃分又細又多,如果採用這種方式,要覆蓋到各種各樣的許可權組合,需要在代碼中定義相當多的角色,大大增加項目維護工作,並且很不靈活。
  這裡借鑒ABP框架中許可權鑒定的一些思想,來實現基於功能點的許可權訪問控制。
  非常感謝ASP.NET Core和ABP等諸多優秀的開源項目,向你們致敬!
  不得不說ABP框架非常優秀,但是我並不喜歡使用它,因為我沒有能力和精力搞清楚它的詳細設計思路,而且很多功能我根本不需要。

思路

  ASP.NET Core提供了一個IAuthorizationFilter介面,如果在控制器類上添加[授權過濾]特性,相應的AuthorizationFilter類的OnAuthorization()方法會在控制器的Action之前運行,如果在該方法中設置AuthorizationFilterContext.Result為一個錯誤的response,Action將不會被調用。

基於這個思路,我們設計了以下方案:

  1. 編寫一個Attribute(特性)類,包含以下兩個屬性:

    Permissions:需要檢查的許可權數組

    RequireAllPermissions:是否需要擁有數組中全部許可權,如果為否則擁有任一許可權即可

  2. 定義一個IPermissionChecker介面,在介面中定義IsGrantedAsync()方法,用於執行許可權鑒定邏輯

  3. 編寫一個AuthorizationFilterAttribute特性類(應用目標為class),通過屬性註入IPermissionChecker實例。然後在OnAuthorization()方法內調用IPermissionChecker實例的IsGrantedAsync()方法,如果該方法返回值為false,則返回403錯誤,否則正常放行。

編寫過濾器類及相關介面

  1. ApiAuthorizeAttribute類

        [AttributeUsage(AttributeTargets.Method)]
        public class ApiAuthorizeAttribute : Attribute, IFilterMetadata
        {
            public string[] Permissions { get; }
    
            public bool RequireAllPermissions { get; set; }
    
            public ApiAuthorizeAttribute(params string[] permissions)
            {
                Permissions = permissions;
            }
        }
  2. IPermissionChecker介面定義

        public interface IPermissionChecker
        {
            Task<bool> IsGrantedAsync(string permissionName);
        }
  3. AuthorizationFilterAttribute類

        [AttributeUsage(AttributeTargets.Class)]
        public class AuthorizationFilterAttribute : Attribute, IAuthorizationFilter
        {
            [Injection] //屬性註入
            public IPermissionChecker PermissionChecker { get; set; } = NullPermissionChecker.Instance;
    
            public void OnAuthorization(AuthorizationFilterContext context)
            {
                if(存在[AllowAnonymous]特性) return;
                var authorizeAttribute = 從context.Filters中析出ApiAuthorizeAttribute
                foreach (var permission in authorizeAttribute.Permissions)
                {
                 //檢查各項許可權
                 var granted = PermissionChecker.IsGrantedAsync(permission).Result;
                }
                if(檢查未通過)
                 context.Result = new ObjectResult("未授權") { StatusCode = 403 };
            }
        }
  4. 配合屬性註入提供NullPermissionChecker類,在IsGrantedAsync()方法內直接返回true。

實現屬性註入

  做好上面的準備,我們應該可以開始著手在項目內應用許可權鑒定功能了,不過ASP.NET Core內置的DI框架並不支持屬性註入,所以還得添加屬性註入的功能。

  1. 定義InjectionAttribute類,用於顯式聲明應用了此特性的屬性將使用依賴註入

    /// <summary>
    /// 在屬性上添加此特性,以聲明該屬性需要使用依賴註入
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class InjectionAttribute : Attribute { }
  2. 添加一個PropertiesAutowiredFilterProvider類,從DefaultFilterProvider類派生

    public class PropertiesAutowiredFilterProvider : DefaultFilterProvider
    {
        private static IDictionary<string, IEnumerable<PropertyInfo>> _publicPropertyCache = new Dictionary<string, IEnumerable<PropertyInfo>>();
    
        public override void ProvideFilter(FilterProviderContext context, FilterItem filterItem)
        {
            base.ProvideFilter(context, filterItem); //在調用基類方法之前filterItem變數不會有值
            var filterType = filterItem.Filter.GetType();
            if (!_publicPropertyCache.ContainsKey(filterType.FullName))
            {
                var ps=filterType.GetProperties(BindingFlags.Public|BindingFlags.Instance)
                    .Where(c => c.GetCustomAttribute<InjectionAttribute>() != null);
                _publicPropertyCache[filterType.FullName] = ps;
            }
    
            var injectionProperties = _publicPropertyCache[filterType.FullName];
            if (injectionProperties?.Count() == 0)
                return;
            //下麵是註入屬性實例的關鍵代碼
            var serviceProvider = context.ActionContext.HttpContext.RequestServices;
            foreach (var item in injectionProperties)
            {
                var service = serviceProvider.GetService(item.PropertyType);
                if (service == null)
                {
                    throw new InvalidOperationException($"Unable to resolve service for type '{item.PropertyType.FullName}' while attempting to activate '{filterType.FullName}'");
                }
                item.SetValue(filterItem.Filter, service);
            }
        }
    }
  3. 還有非常關鍵的一步,在Startup.ConfigureServices()中添加下麵的代碼,替換IFilterProvider介面的實現類為上面編寫的PropertiesAutowiredFilterProvider

    services.Replace(ServiceDescriptor.Singleton<Microsoft.AspNetCore.Mvc.Filters.IFilterProvider, PropertiesAutowiredFilterProvider>());

實現用戶許可權鑒定

  終於,我們可以在項目內應用許可權鑒定功能了。

編碼

  1. 首先,我們定義一些功能點許可權常量

    public static class PermissionNames
    {
        public const string TestAdd = "Test.Add";
        public const string TestEdit = "Test.Edit";
        public const string TestDelete = "Test.Delete";
    }
  2. 接著,添加一個新的用於測試的控制器類

        [AuthorizationFilter]
        [Route("api/[controller]")]
        [ApiController]
        public class TestController : ControllerBase
        {
            [Injection]
            public IClaimsSession Session { get; set; }
    
            [HttpGet]
            [Route("[action]")]
            public IActionResult CurrentUser() => Ok(Session?.UserName);
    
            [ApiAuthorize]
            [HttpGet("{id}")]
            public IActionResult Get(int id)=> Ok(id);
    
            [ApiAuthorize(PermissionNames.TestAdd)]
            [HttpPost]
            [Route("[action]")]
            public IActionResult Create()=> Ok();
    
            [ApiAuthorize(PermissionNames.TestEdit, RequireAllPermissions = false)]
            [HttpPost]
            [Route("[action]")]
            public IActionResult Update()=> Ok();
    
            [ApiAuthorize(PermissionNames.TestAdd, PermissionNames.TestEdit, RequireAllPermissions = false)]
            [HttpPost]
            [Route("[action]")]
            public IActionResult Patch() => Ok();
    
            [ApiAuthorize(PermissionNames.TestDelete)]
            [HttpDelete("{id}")]
            public IActionResult Delete(int id) => Ok();
        }

    在控制器類上添加了[AuthorizationFilter]特性,除了CurrentUser()方法以外,都添加了[ApiAuthorize]特性,所需的許可權各不相同,為簡化測試所有的Action都直接返回OkResult

  3. 實現一個用於演示的許可權檢查器類

    public class SamplePermissionChecker : IPermissionChecker
    {
        private readonly Dictionary<long, string[]> userPermissions = new Dictionary<long, string[]>
        {
            //Id=1的用戶具有Test模塊的全部功能
            { 1, new[] { PermissionNames.TestAdd, PermissionNames.TestEdit, PermissionNames.TestDelete } },
            //Id=2的用戶具有Test模塊的編輯和刪除功能
            { 2, new[] { PermissionNames.TestEdit, PermissionNames.TestDelete } }
        };
    
        public IClaimsSession Session { get; }
    
        //通過構造函數註入IClaimsSession實例,以便在許可權鑒定方法中獲取用戶信息
        public SamplePermissionChecker(IClaimsSession session)
        {
            this.Session = session;
        }
    
        public Task<bool> IsGrantedAsync(string permissionName)
        {
            if(!userPermissions.Any(p => p.Key == Session.UserId))
                return Task.FromResult(false);
            var up = userPermissions.Where(p => p.Key == Session.UserId).First();
            var granted = up.Value.Any(permission => permission.Equals(permissionName, StringComparison.InvariantCultureIgnoreCase));
            return Task.FromResult(granted);
        }
    
    }
  4. 最後還需要修改項目中Startup.cs文件,添加依賴註入規則

    services.AddSingleton<IPermissionChecker, SamplePermissionChecker>();

    因為SamplePermissionChecker類中並沒有需要進程間隔離的數據,所以使用單例模式註冊就可以了。不過這樣一來,因為該類通過構造函數註入了IClaimsSession介面實例,在構建Checker類實例時將觸發異常。考慮到CliamsSession類中只有方法沒有數據 ,改為單例也並無妨,於是將該介面也改為單例模式註冊。

通過Swagger測試

  • 測試未登錄時僅可訪問/api/Test/CurrentUser

  • 測試以用戶user登錄,可以訪問/api/Test/CurrentUser和GET請求/api/Test/{id}

  • 測試以用戶admin登錄,可以訪問除/api/Test/Add以外的介面

測試

編寫了命令行程式,用來測試前面實現的Web API服務。

測試不同用戶同時訪問時Session是否正確

  • 測試方法

    同時運行三個測試程式,都選擇[測試身份驗證],然後分別輸入不同的用戶身份序號,快速切換三個程式並按下回車鍵,三個測試程式會各自發起100次請求,每次請求間隔100毫秒。

    例如同時打開三個命令行終端執行:dotnet .\CustomAuthorization.test.dll

  • 測試結果

    三個測試程式從後臺服務所獲取到的當前用戶信息完全匹配。

測試以不同用戶身份訪問需要許可權的介面

  • 測試方法

    預設的許可權為:admin=>全部許可權,user=>除Test.Add以外許可權,tester=>無。

    分別以admin、user、tester三個用戶身份請求/api/test下的所有介面,並模擬令牌過期的場景。

  • 測試結果

    可以見到,以過期的令牌發起請求時,後臺返回的狀態為Unauthorized,當用戶未獲得足夠的授權時後臺返回的狀態為Forbidden。

    測試通過!

最後

源代碼托管在gitee.com
歡迎轉載,請在明顯位置給出出處及鏈接


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • filter() 過濾1.結構 filter(func, iterable) ---- func函數的返回值為True,迭代iterable每個元素執行func,True則保留;False則捨去 ---- func可以使內置函數,也可以是用戶聲明的函數2.返回值 ---- fi... ...
  • 最近需要完成一個javaweb項目,但是沒有和資料庫連接而是通過websocket通訊實現和伺服器端數據交互。我搜了好多,網上大部分都是通過頁面websocket連接本地伺服器或連接異地伺服器,但是這些都把連接地址暴露在了外面,不是我想要的。本人希望websocket連接、數據處理等都是在java後 ...
  • 前言 很多人覺得Xamarin的開源少,沒法用來開發項目。 但,實際上Xamarin已經有很多開源代碼了;只要不是特別特殊的項目,基本上是都可以滿足開發。 下麵我們來看一下Xamarin中利用開源代碼ZXing.Net.Mobile進行掃碼。 引用ZXing.Net.Mobile 在Xamarin中 ...
  • @[toc] 前言 有三個重要的類Claim, ClaimsIdentity, ClaimsPrincipal,我們以一個持有合法證件的學生Bob做比方,ClaimsPrincipal就是持有證件的學生Bob,ClaimsIdentity就是學生Bob的證件駕照,Claim就是Bob駕照中的各種信息 ...
  • 在虛擬機中安裝CentOS7碰到的問題以及解決方法 1.安裝之後想通過CRT遠程連接獲,輸入ifconfig查看系統ip報錯誤:ifconfig command not found,報此錯誤是由於初次安裝的CentOS是未啟用網路的,所以我們需要啟用網路 2.所以需要打開network,需執行如下命 ...
  • net core 和普通net 發佈沒有什麼不同,只需要在個別地方註意下: 1. 在visual Studio 2017 發佈 2. 把發佈好的文件copy到伺服器上,並新建一個網站,同時要註意選擇無托管代碼 3.此時訪問介面,會報錯,是因為沒有安裝 window server Hosting,它的 ...
  • 今天工作中遇到了一個情景: 前端向後臺發送一個請求,希望後臺返回一組數據,由於後臺返回的數據量很大,希望儘可能壓縮響應的大小 我的想法:後臺將數據(Short的數組)直接轉換成Byte[] 然後將byte[]發送至前端。 傳統的Json是將數據序列化成Json文件在發送到前端,這樣做的好處是處理簡單 ...
  • 系統:WIndows 10 工具:Visual Studio 2017 在寫代碼的過程中,我遇到了這樣的一個問題。如圖 vs錯誤提示是在SqlHelper中有錯,可是怎麼改都不能解決問題。 最後發現是前端往後端傳數據的時候,多寫了一個Id,如圖 在下麵編號中我已經回傳了一個Id的值,就不再需要一個h ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...