透過Process的方式去掉用java及javac,並且將結果透過async方式取得避免線程賭塞
關於CSRF的介紹可以參考這篇「讓我們來談談 CSRF」
Startup.cs
這邊要在ConfigureServices加入
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
要設定這個主要是因為XSRF/CSRF
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace WebOnlineEditorApplication
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc();
}
}
}
Index.cshtml
前端部分主要如下的程式碼
不過做ajax時需要加入,不然會有XSRF/CSRF導致無法呼叫
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script>
$(document).ready(function () {
$('#btn_run').click(function (e) {
$code = $('#code').val();
$.ajax({
url: '/?handler=Result',
type: 'GET',
data: {
code:$code
},
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
dataType:"json"
}).done(function (data) {
$('#result').val(data);
});
});
});
</script>
<div>
<textarea id="code" rows="10" cols="50"></textarea><br />
<button id="btn_run">Run</button><br />
<textarea id="result" rows="10" cols="50"></textarea><br />
</div>
後端程式碼則需要再該呼叫的方法上加上
[ValidateAntiForgeryToken]
Index.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;
namespace WebOnlineEditorApplication.Pages
{
public class IndexModel : PageModel
{
/// <summary>
///
/// </summary>
private readonly static String COMPILER_PATH = @"C:\Program Files\Java\jdk-11.0.2\bin\javac";
/// <summary>
///
/// </summary>
private readonly static String RUN_PATH = @"C:\Program Files\Java\jdk-11.0.2\bin\java";
/// <summary>
///
/// </summary>
private readonly static String JAVA = "{0}.java";
/// <summary>
/// Get Result
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
[ValidateAntiForgeryToken]
public async Task<JsonResult> OnGetResult(String code)
{
JsonResult result = null;
String className = code.Split(Environment.NewLine)[0].Substring(code.IndexOf("s") + 2, code.IndexOf('{') - code.IndexOf("s") - 2).Replace(" ", "");
String path = Directory.GetCurrentDirectory() + @"\";
if (code != null && !code.Equals(String.Empty))
{
using (FileStream stream = new FileStream(String.Format(JAVA, className), FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
byte[] b = Encoding.UTF8.GetBytes(code);
await stream.WriteAsync(b, 0, b.Length);
stream.Flush();
}
}
String resultMsg = String.Empty;
String errMsg = String.Empty;
using (Process process = new Process())
{
process.StartInfo.FileName = COMPILER_PATH;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.FileName = COMPILER_PATH;
process.StartInfo.Arguments = String.Format(JAVA, path + className);
process.Start();
resultMsg = await process.StandardOutput.ReadToEndAsync();
errMsg = await process.StandardError.ReadToEndAsync();
process.WaitForExit();
Debug.WriteLine(errMsg);
}
if (System.IO.File.Exists(String.Format(JAVA, className)))
System.IO.File.Delete(String.Format(JAVA, className));
if (!errMsg.Equals(String.Empty))
{
result = new JsonResult(errMsg);
return result;
}
else
{
using (Process process = new Process())
{
process.StartInfo.FileName = RUN_PATH;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.FileName = RUN_PATH;
process.StartInfo.Arguments = className;
process.StartInfo.WorkingDirectory = path;
process.Start();
resultMsg = await process.StandardOutput.ReadToEndAsync();
errMsg = await process.StandardError.ReadToEndAsync();
process.WaitForExit();
}
if (errMsg.Equals(String.Empty))
{
result = new JsonResult(errMsg);
}
result = new JsonResult(resultMsg);
}
if (System.IO.File.Exists(String.Format("{0}.class", className)))
System.IO.File.Delete(String.Format("{0}.class", className));
return result;
}
/// <summary>
///
/// </summary>
public void OnGet()
{
}
}
}
執行結果:
參考資料:
https://docs.microsoft.com/zh-tw/aspnet/core/security/anti-request-forgery?view=aspnetcore-2.2
https://blog.techbridge.cc/2017/02/25/csrf-introduction/