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 应用也 ...
随机推荐
- openfire:基于开源 Openfire 聊天服务器 - 开发Openfire聊天记录插件
基于开源 Openfire 聊天服务器 - 开发Openfire聊天记录插件 上一篇文章介绍到怎么在自己的Java环境中搭建openfire插件开发的环境,同时介绍到怎样一步步简单的开发openfir ...
- java.lang.IllegalArgumentException: Result Maps collection already contains value for
如果在SSM整合的时候出现以下的错误: 留意一下是不是既在Mybatis配置文件中加载了映射文件,又在Spring配置文件中使用扫描式去加载映射文件了.两者是不能够重合使用的! Caused by: ...
- Hibernate的注解方法的使用
1.配置映射关系的xml方式 我们知道,Hibernate是一个典型的ORM框架,用以解决对象和关系的不匹配.其思想就是将关系数据库中表的记录映射成为对象,以对象形式展现,这样一来,就可以把对数据库的 ...
- PeopleRank
PeopleRank:基于PageRank的理论,以每个微博账户的“关注”为链出链接,“粉丝”为链入链接的这种以人为核心的关系. PeopleRank假设条件:– 数量假设:如果一个用户节点接收到的其 ...
- oracle 数据库管理--管理表空间和数据文件
一.概念表空间是数据库的逻辑组成部分.从物理上讲,数据库数据存放在数据文件中:从逻辑上讲,数据库数据则是存放在表空间中,表空间由一个或多个数据文件组成. 二.数据库的逻辑结构oracle中逻辑结构包括 ...
- foreach循环中为什么不要进行remove/add操作
先来看一段代码,摘自阿里巴巴的java开发手册 List<String> a = new ArrayList<String>(); a.add("1"); ...
- MMORPG战斗系统随笔(一)
前言 很久没有更新博客,中间迁移过一次博客,后来一直忙于项目的开发,忙的晚上回去没时间写博客,周日又要自我调整一下,所以空闲了很久没有继续写博客.最近终于慢慢放慢节奏,项目也快上线了,可以有空写一些个 ...
- 新版本mac 无法打开第三方应用
新版本mac 没有任何应用可以打开的这个选项 现在解决方法已经找到 特此标记一下 1打开终端 2 输入 sudo spctl --master-disable 3.打开系统设置的中的安全即可出现
- java复习要点(一)------- java语言的特点、java的工作原理、配置环境变量、java命令的使用
一.java语言的特点: (1)简单并面向对象 (2)鲁棒并安全: java语言在编译及运行程序时,都要进行严格的检查,防止不匹配问题的发生.如果引用一个非法类型,或执行一个非法类型操作,java减肥 ...
- Integer的自动拆箱
public class Test2{ public static void main(String[] args){ Integer a=1; Integer b=2; Integer c=3; I ...