ASP.NET Core 开源GitServer 实现自己的GitHub
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 = ; i < ; 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
public class BasicAuthenticationHandler : AuthenticationHandler<BasicAuthenticationOptions>
{
public BasicAuthenticationHandler(IOptionsMonitor<BasicAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{ }
protected async override Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Headers.ContainsKey("Authorization"))
return AuthenticateResult.NoResult(); string authHeader = Request.Headers["Authorization"];
if (!authHeader.StartsWith("Basic ", StringComparison.OrdinalIgnoreCase))
return AuthenticateResult.NoResult(); string token = authHeader.Substring("Basic ".Length).Trim();
string credentialString = Encoding.UTF8.GetString(Convert.FromBase64String(token));
string[] credentials = credentialString.Split(':'); if (credentials.Length != )
return AuthenticateResult.Fail("More than two strings seperated by colons found"); ClaimsPrincipal principal = await Options.SignInAsync(credentials[], credentials[]); if (principal != null)
{
AuthenticationTicket ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), BasicAuthenticationDefaults.AuthenticationScheme);
return AuthenticateResult.Success(ticket);
} return AuthenticateResult.Fail("Wrong credentials supplied");
}
protected override Task HandleForbiddenAsync(AuthenticationProperties properties)
{
Response.StatusCode = ;
return base.HandleForbiddenAsync(properties);
} protected override Task HandleChallengeAsync(AuthenticationProperties properties)
{
Response.StatusCode = ;
string headerValue = $"{BasicAuthenticationDefaults.AuthenticationScheme} realm=\"{Options.Realm}\"";
Response.Headers.Append(Microsoft.Net.Http.Headers.HeaderNames.WWWAuthenticate, headerValue);
return base.HandleChallengeAsync(properties);
}
} public class BasicAuthenticationOptions : AuthenticationSchemeOptions, IOptions<BasicAuthenticationOptions>
{
private string _realm; public IServiceCollection ServiceCollection { get; set; }
public BasicAuthenticationOptions Value => this;
public string Realm
{
get { return _realm; }
set
{
_realm = value;
}
} public async Task<ClaimsPrincipal> SignInAsync(string userName, string password)
{
using (var serviceScope = ServiceCollection.BuildServiceProvider().CreateScope())
{
var _user = serviceScope.ServiceProvider.GetService<IRepository<User>>();
var user = _user.List(r => r.Name == userName && r.Password == password).FirstOrDefault();
if (user == null)
return null;
var identity = new ClaimsIdentity(BasicAuthenticationDefaults.AuthenticationScheme, ClaimTypes.Name, ClaimTypes.Role);
identity.AddClaim(new Claim(ClaimTypes.Name, user.Name));
var principal = new ClaimsPrincipal(identity);
return principal;
}
}
} public static class BasicAuthenticationDefaults
{
public const string AuthenticationScheme = "Basic";
}
public static class BasicAuthenticationExtensions
{
public static AuthenticationBuilder AddBasic(this AuthenticationBuilder builder)
=> builder.AddBasic(BasicAuthenticationDefaults.AuthenticationScheme, _ => { _.ServiceCollection = builder.Services;_.Realm = "GitServer"; }); public static AuthenticationBuilder AddBasic(this AuthenticationBuilder builder, Action<BasicAuthenticationOptions> configureOptions)
=> builder.AddBasic(BasicAuthenticationDefaults.AuthenticationScheme, configureOptions); public static AuthenticationBuilder AddBasic(this AuthenticationBuilder builder, string authenticationScheme, Action<BasicAuthenticationOptions> configureOptions)
=> builder.AddBasic(authenticationScheme, displayName: null, configureOptions: configureOptions); public static AuthenticationBuilder AddBasic(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<BasicAuthenticationOptions> configureOptions)
{
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IOptions<BasicAuthenticationOptions>, BasicAuthenticationOptions>());
return builder.AddScheme<BasicAuthenticationOptions, BasicAuthenticationHandler>(authenticationScheme, displayName, configureOptions);
}
}
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的更多相关文章
- ASP.NET Core 开源项目整理
前言: 对 .NET Core 的热情一直没有下降过,新起的项目几乎都是采用 Core 来做开发. 跨平台是一个方面,另外就是 Core 很轻,性能远超很多开发语言(不坑). 一.ASP.NET Co ...
- ASP.NET Core DotNetCore 开源GitServer 实现自己的GitHub
ASP.NET Core 2.0 开源Git HTTP Server,实现类似 GitHub.GitLab. GitHub:https://github.com/linezero/GitServer ...
- ASP.NET Core 开源论坛项目 NETCoreBBS
ASP.NET Core 轻量化开源论坛项目,ASP.NET Core Light forum NETCoreBBS 采用 ASP.NET Core + EF Core Sqlite + Bootst ...
- ASP.NET Core开源地址
https://github.com/dotnet/corefx 这个是.net core的 开源项目地址 https://github.com/aspnet 这个下面是asp.net core 框架 ...
- asp.net core开源项目
Orchard框架:https://www.xcode.me/code/asp-net-core-cms-orchard https://orchardproject.net/ https://git ...
- 【分享】Asp.net Core相关教程及开源项目
入门 全新的ASP.NET: https://www.cnblogs.com/Leo_wl/p/5654828.html 在IIS上部署你的ASP.NET Core项目: https://www.c ...
- Asp.net Core相关教程及开源项目推荐
入门 全新的ASP.NET: https://www.cnblogs.com/Leo_wl/p/5654828.html 在IIS上部署你的ASP.NET Core项目: https://www.c ...
- ASP.NET Core 介绍
原文:Introduction to ASP.NET Core 作者:Daniel Roth.Rick Anderson.Shaun Luttin 翻译:江振宇(Kerry Jiang) 校对:许登洋 ...
- ASP.NET Core开发-后台任务利器Hangfire使用
ASP.NET Core开发系列之后台任务利器Hangfire 使用. Hangfire 是一款强大的.NET开源后台任务利器,无需Windows服务/任务计划程序. 可以使用于ASP.NET 应用也 ...
随机推荐
- Could not instantiate bean class [org.springframework.web.multipart.MultipartFile]: Specified class
如果在使用SpringMVC中使用文件上传的MultipartFile对象时,出现了以下的错误: Could not instantiate bean class [org.springframewo ...
- Spring第三篇【Core模块之对象依赖】
前言 在Spring的第二篇中主要讲解了Spring Core模块的使用IOC容器创建对象的问题,Spring Core模块主要是解决对象的创建和对象之间的依赖关系,因此本博文主要讲解如何使用IOC容 ...
- docker应用笔记
first install it: 首先安装: apt install docker.io 基本概念: 镜像:相当于虚拟机里的磁盘文件,里面有一套配置好的系统,应用程序 容器:相当于一个虚拟机实例,一 ...
- oracle "记录被另一个用户锁定"
出现的原因是有人对某一条数据进行了修改,oracle会通过这个事务记住这条数据,若修改的人没有进行提交或进行回滚记录,oracle是不允许对这条数据在此进行修改的,在这种情况下你要进行修改数据,则会被 ...
- (转)添加PROPAGATION_REQUIRES_NEW 事务没有产生作用
最近在做事务添加时 发现自己的事务没有新建,上网查到 仅用作收藏. 其二 注意 事务的注解 应该在 内层的事务上面 一.描述 Spring遇到嵌套事务时,当被嵌套的事务被定义为" ...
- 用vue开发一个app(3,三天的成果)
前言 一个vue的demo 源码说明 项目目录说明 . |-- config // 项目开发环境配置 | |-- index.js // 项目打包部署配置 |-- src // 源码目录 | |-- ...
- A glimpse of Support Vector Machine
支持向量机(support vector machine, 以下简称svm)是机器学习里的重要方法,特别适用于中小型样本.非线性.高维的分类和回归问题.本篇希望在正篇提供一个svm的简明阐述,附录则提 ...
- Jupyter(Python)中无法使用Cache原理分析
前言 最近需要在Jupyter中写一个类库,其中有一个文件实现从数据库中读取空间数据并加载为Feature对象,Feature对象是cartopy封装的geomery列表,能够方便的用于作图等.因为有 ...
- 已被.NET基金会认可的弹性和瞬态故障处理库Polly介绍
前言 本节我们来介绍一款强大的库Polly,Polly是一种.NET弹性和瞬态故障处理库,允许我们以非常顺畅和线程安全的方式来执诸如行重试,断路,超时,故障恢复等策略. Polly针对对.NET 4. ...
- 怎样使用自定义标签简化 js、css 引入?
国庆将至,工作兴致全无,来总结点项目里平时不起眼干货. 前端引入 js .css 一般是这样: <script type="text/javascript" src=&quo ...