ASP.NET Core 開源GitServer 實現自己的GitHub

来源:http://www.cnblogs.com/linezero/archive/2017/10/28/gitserver.html
-Advertisement-
Play Games

ASP.NET Core 2.0 開源Git HTTP Server,實現類似 GitHub、GitLab。 GitHub:https://github.com/linezero/GitServer 設置 需要先安裝Git,並確保git 命令可以執行,GitPath 可以是 git 的絕對路徑。 目 ...


ASP.NET Core 2.0 開源Git HTTP Server,實現類似 GitHub、GitLab。

GitHub:https://github.com/linezero/GitServer

設置

  "GitSettings": {
    "BasePath": "D:\\Git",
    "GitPath": "git"
  }

需要先安裝Git,並確保git 命令可以執行,GitPath 可以是 git 的絕對路徑。

目前實現的功能

  • 創建倉庫
  • 瀏覽倉庫
  • git客戶端push pull
  • 資料庫支持 SQLite、MSSQL、MySQL
  • 支持用戶管理倉庫

更多功能可以查看readme,也歡迎大家貢獻支持。

Git交互

LibGit2Sharp 用於操作Git庫,實現創建讀取倉庫信息及刪除倉庫。

以下是主要代碼:

        public Repository CreateRepository(string name)
        {
            string path = Path.Combine(Settings.BasePath, name);
            Repository repo = new Repository(Repository.Init(path, true));
            return repo;
        }

        public Repository CreateRepository(string name, string remoteUrl)
        {
            var path = Path.Combine(Settings.BasePath, name);
            try
            {
                using (var repo = new Repository(Repository.Init(path, true)))
                {
                    repo.Config.Set("core.logallrefupdates", true);
                    repo.Network.Remotes.Add("origin", remoteUrl, "+refs/*:refs/*");
                    var logMessage = "";
                    foreach (var remote in repo.Network.Remotes)
                    {
                        IEnumerable<string> refSpecs = remote.FetchRefSpecs.Select(x => x.Specification);
                        Commands.Fetch(repo, remote.Name, refSpecs, null, logMessage);
                    }
                    return repo;
                }                
            }
            catch
            {
                try
                {
                    Directory.Delete(path, true);
                }
                catch { }
                return null;
            }
        }

        public void DeleteRepository(string name)
        {
            Exception e = null;
            for(int i = 0; i < 3; i++)
            {
                try
                {
                    string path = Path.Combine(Settings.BasePath, name);
                    Directory.Delete(path, true);

                }
                catch(Exception ex) { e = ex; }
            }

            if (e != null)
                throw new GitException("Failed to delete repository", e);
        }

 

執行Git命令

git-upload-pack 

git-receive-pack

主要代碼 GitCommandResult 實現IActionResult

public async Task ExecuteResultAsync(ActionContext context)
        {
            HttpResponse response = context.HttpContext.Response;
            Stream responseStream = GetOutputStream(context.HttpContext);

            string contentType = $"application/x-{Options.Service}";
            if (Options.AdvertiseRefs)
                contentType += "-advertisement";

            response.ContentType = contentType;

            response.Headers.Add("Expires", "Fri, 01 Jan 1980 00:00:00 GMT");
            response.Headers.Add("Pragma", "no-cache");
            response.Headers.Add("Cache-Control", "no-cache, max-age=0, must-revalidate");

            ProcessStartInfo info = new ProcessStartInfo(_gitPath, Options.ToString())
            {
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardInput = true,
                RedirectStandardOutput = true,
                RedirectStandardError = true
            };

            using (Process process = Process.Start(info))
            {
                GetInputStream(context.HttpContext).CopyTo(process.StandardInput.BaseStream);

                if (Options.EndStreamWithNull)
                    process.StandardInput.Write('\0');
                process.StandardInput.Dispose();

                using (StreamWriter writer = new StreamWriter(responseStream))
                {
                    if (Options.AdvertiseRefs)
                    {
                        string service = $"# service={Options.Service}\n";
                        writer.Write($"{service.Length + 4:x4}{service}0000");
                        writer.Flush();
                    }

                    process.StandardOutput.BaseStream.CopyTo(responseStream);
                }

                process.WaitForExit();
            }
        }

 

BasicAuthentication 基本認證實現

git http 預設的認證為Basic 基本認證,所以這裡實現Basic 基本認證。

在ASP.NET Core 2.0 中 Authentication 變化很大之前1.0的一些代碼是無法使用。

首先實現 AuthenticationHandler,然後實現  AuthenticationSchemeOptions,創建 BasicAuthenticationOptions。

最主要就是這兩個類,下麵兩個類為輔助類,用於配置和中間件註冊。

更多可以查看官方文檔

身份驗證

https://docs.microsoft.com/zh-cn/aspnet/core/security/authentication/

https://docs.microsoft.com/zh-cn/aspnet/core/migration/1x-to-2x/identity-2x

 1    public class BasicAuthenticationHandler : AuthenticationHandler<BasicAuthenticationOptions>
 2     {
 3         public BasicAuthenticationHandler(IOptionsMonitor<BasicAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
 4             : base(options, logger, encoder, clock)
 5         { }
 6         protected async override Task<AuthenticateResult> HandleAuthenticateAsync()
 7         {
 8             if (!Request.Headers.ContainsKey("Authorization"))
 9                 return AuthenticateResult.NoResult();
10 
11             string authHeader = Request.Headers["Authorization"];
12             if (!authHeader.StartsWith("Basic ", StringComparison.OrdinalIgnoreCase))
13                 return AuthenticateResult.NoResult();
14 
15             string token = authHeader.Substring("Basic ".Length).Trim();
16             string credentialString = Encoding.UTF8.GetString(Convert.FromBase64String(token));
17             string[] credentials = credentialString.Split(':');
18 
19             if (credentials.Length != 2)
20                 return AuthenticateResult.Fail("More than two strings seperated by colons found");
21 
22             ClaimsPrincipal principal = await Options.SignInAsync(credentials[0], credentials[1]);
23 
24             if (principal != null)
25             {
26                 AuthenticationTicket ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), BasicAuthenticationDefaults.AuthenticationScheme);
27                 return AuthenticateResult.Success(ticket);
28             }
29 
30             return AuthenticateResult.Fail("Wrong credentials supplied");
31         }
32         protected override Task HandleForbiddenAsync(AuthenticationProperties properties)
33         {
34             Response.StatusCode = 403;
35             return base.HandleForbiddenAsync(properties);
36         }
37 
38         protected override Task HandleChallengeAsync(AuthenticationProperties properties)
39         {
40             Response.StatusCode = 401;
41             string headerValue = $"{BasicAuthenticationDefaults.AuthenticationScheme} realm=\"{Options.Realm}\"";
42             Response.Headers.Append(Microsoft.Net.Http.Headers.HeaderNames.WWWAuthenticate, headerValue);
43             return base.HandleChallengeAsync(properties);
44         }
45     }
46 
47     public class BasicAuthenticationOptions : AuthenticationSchemeOptions, IOptions<BasicAuthenticationOptions>
48     {
49         private string _realm;
50 
51         public IServiceCollection ServiceCollection { get; set; }
52         public BasicAuthenticationOptions Value => this;
53         public string Realm
54         {
55             get { return _realm; }
56             set
57             {
58                 _realm = value;
59             }
60         }
61 
62         public async Task<ClaimsPrincipal> SignInAsync(string userName, string password)
63         {
64             using (var serviceScope = ServiceCollection.BuildServiceProvider().CreateScope())
65             {
66                 var _user = serviceScope.ServiceProvider.GetService<IRepository<User>>();
67                 var user = _user.List(r => r.Name == userName && r.Password == password).FirstOrDefault();
68                 if (user == null)
69                     return null;
70                 var identity = new ClaimsIdentity(BasicAuthenticationDefaults.AuthenticationScheme, ClaimTypes.Name, ClaimTypes.Role);
71                 identity.AddClaim(new Claim(ClaimTypes.Name, user.Name));
72                 var principal = new ClaimsPrincipal(identity);
73                 return principal;
74             }
75         }
76     }
77 
78     public static class BasicAuthenticationDefaults
79     {
80         public const string AuthenticationScheme = "Basic";
81     }
82     public static class BasicAuthenticationExtensions
83     {
84         public static AuthenticationBuilder AddBasic(this AuthenticationBuilder builder)
85             => builder.AddBasic(BasicAuthenticationDefaults.AuthenticationScheme, _ => { _.ServiceCollection = builder.Services;_.Realm = "GitServer"; });
86 
87         public static AuthenticationBuilder AddBasic(this AuthenticationBuilder builder, Action<BasicAuthenticationOptions> configureOptions)
88             => builder.AddBasic(BasicAuthenticationDefaults.AuthenticationScheme, configureOptions);
89 
90         public static AuthenticationBuilder AddBasic(this AuthenticationBuilder builder, string authenticationScheme, Action<BasicAuthenticationOptions> configureOptions)
91             => builder.AddBasic(authenticationScheme, displayName: null, configureOptions: configureOptions);
92 
93         public static AuthenticationBuilder AddBasic(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<BasicAuthenticationOptions> configureOptions)
94         {
95             builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IOptions<BasicAuthenticationOptions>, BasicAuthenticationOptions>());
96             return builder.AddScheme<BasicAuthenticationOptions, BasicAuthenticationHandler>(authenticationScheme, displayName, configureOptions);
97         }
98     }
View Code

 

CookieAuthentication Cookie認證

實現自定義登錄,無需identity ,實現註冊登錄。

主要代碼:

啟用Cookie

https://github.com/linezero/GitServer/blob/master/GitServer/Startup.cs#L60

services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            }).AddCookie(options=> {
                options.AccessDeniedPath = "/User/Login";
                options.LoginPath = "/User/Login";
            })

登錄

https://github.com/linezero/GitServer/blob/master/GitServer/Controllers/UserController.cs#L34

                    var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme, ClaimTypes.Name, ClaimTypes.Role);
                    identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Name));
                    identity.AddClaim(new Claim(ClaimTypes.Name, user.Name));
                    identity.AddClaim(new Claim(ClaimTypes.Email, user.Email));
                    var principal = new ClaimsPrincipal(identity);
                    await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);

官方文檔介紹:https://docs.microsoft.com/zh-cn/aspnet/core/security/authentication/cookie?tabs=aspnetcore2x

部署說明

發佈後配置資料庫及git目錄(可以為絕對地址和命令)、git 倉庫目錄。

{
  "ConnectionStrings": {
    "ConnectionType": "Sqlite", //Sqlite,MSSQL,MySQL
    "DefaultConnection": "Filename=gitserver.db"
  },
  "GitSettings": {
    "BasePath": "D:\\Git",
    "GitPath": "git"
  }
}

運行後註冊賬戶,登錄賬戶創建倉庫,然後根據提示操作,隨後git push、git pull 都可以。

 


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

-Advertisement-
Play Games
更多相關文章
  • 第一步:# vi /etc/sysconfig/network-scripts/ifcfg-bond0 DEVICE=bond0 BONDING_OPTS="mode=0 miimon=100" BOOTPROTO=none ONBOOT=yes BROADCAST=192.168.0.255 IP ...
  • 上篇文章介紹瞭如何在ASP.NET MVC項目中引入Identity組件來實現用戶註冊、登錄及身份驗證功能,並且也提到了Identity是集成到Owin中的,本章就來介紹一下什麼是Owin以及如何使用Owin來增強Identity的功能。 本章的主要內容有: ● 什麼是Owin ● 關於Katana ...
  • 今天跟著學習了一篇關於表格的排序、過濾與分頁功能的博客,下邊分享一下學到的知識與心得: 一、應用之前樣式,增加測試數據 對Views —— Account —— Index.cshtml進行如下修改: (1)應用佈局頁 _LayoutAdmin.cshtml @{ ViewBag.Title = " ...
  • .Net常用類庫 一、String成員方法(常用) 1,bool Contains(string str) 判斷字元串對象是否包含給定的內容 2,bool StartsWith(String str):判斷字元串對象是否以給定的字元串開始。 3,bool EndsWith(String str):判 ...
  • 前言作為一名合格的furry,我不僅要吸娜娜奇,還要天天泡在fa吸大觸們的furry作品,這其中難免遇到某個十分喜愛的作者,於是便想down空此作者的所有作品。鑒於一張張的保存實在費時費力,寫個爬蟲來解決眼前的問題似乎再好不過了,所以便有了現在這個下載器。功能介紹根據作者名批量下載此作者的所有作品,... ...
  • 這是今天幫 "檸檬" 分析一個 "AsyncLocal相關的問題" 時發現的. 試想這個代碼輸出的值是多少? 答案是123. 為什麼修改了 的值卻無效呢? 這要從AsyncLocal的運作機制說起. 首先這是 "AsyncLocal的源代碼" : 獲取和設置值用的是 和`ExecutionConte ...
  • WCF系統內置綁定列表 編碼格式 一個綁定,適用於與符合 WS-Basic Profile的Web服務(例如基於 ASP.NET Web 服務(ASMX)的服務)進行的通信。 此綁定使用HTTP作為傳輸協議,並使用文本/XML作為預設的消息編碼 Text, MTOM WCF各系統綁定所支持的功能 ...
  • 在 "上一篇" 我們對CoreCLR中的JIT有了一個基礎的瞭解, 這一篇我們將更詳細分析JIT的實現. JIT的實現代碼主要在 "https://github.com/dotnet/coreclr/tree/master/src/jit" 下, 要對一個的函數的JIT過程進行詳細分析, 最好的辦法 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...