分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 教程案例

ASP.NET Core 开源GitServer 实现自己的GitHub

发布时间:2023-09-06 01:20责任编辑:赖小花关键词:.NET

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 Realm54 ????????{55 ????????????get { return _realm; }56 ????????????set57 ????????????{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 BasicAuthenticationDefaults79 ????{80 ????????public const string AuthenticationScheme = "Basic";81 ????}82 ????public static class BasicAuthenticationExtensions83 ????{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 都可以。

ASP.NET Core 开源GitServer 实现自己的GitHub

原文地址:http://www.cnblogs.com/linezero/p/gitserver.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved