正如this doc中所述,我按如下方式设置了我的Startup类:
public class Startup
{
public Startup(IHostingEnvironment environment, IConfiguration configuration)
{
Environment = environment;
Configuration = configuration;
}
public IHostingEnvironment Environment { get; }
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
var secretsFolder = Path.Combine(Configuration["SecretsFolder"].Split('/'));
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(Path.Combine(secretsFolder, "keys")));
services.AddDbContext<ApplicationDbContext>(options =>
{
var connectionString = Configuration["MyAppDbConnectionString"] +
"User ID=" + Configuration["DatabaseUser"] +
";Password=" + Configuration["DatabasePassword"] + ";";
options.UseNpgsql(connectionString);
});
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.Name = ".MyApp.Identity";
options.Cookie.HttpOnly = true;
options.Cookie.Expiration = TimeSpan.FromDays(30);
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.SlidingExpiration = true;
options.LoginPath = "/Account/Login";
options.LogoutPath = "/Account/Logout";
options.AccessDeniedPath = "/Account/AccessDenied";
});
services.AddAntiforgery(options =>
{
options.Cookie.Name = ".MyApp.AntiCSRF";
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});
services.Configure<MvcOptions>(options =>
{
// See https://docs.microsoft.com/en-us/aspnet/core/security/enforcing-ssl
options.Filters.Add(new RequireHttpsAttribute());
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
// Make authentication compulsory by default;
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
// See https://docs.microsoft.com/en-us/aspnet/core/security/enforcing-ssl
var options = new RewriteOptions().AddRedirectToHttps();
app.UseRewriter(options);
if (Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
在Ubuntu 16.04上,我从默认的ubuntu repo安装了Nginx,然后安装了LetsEncrypt。以下是/ etc / nginx / sites-available / default文件的内容:
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
server {
listen 80;
server_name myapp.com;
root /home/me/myapp/wwwroot;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/myapp.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/myapp.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
if ($scheme != "https") {
return 301 https://$host$request_uri;
} # managed by Certbot
}
请注意,我还没有更改/etc/nginx/nginx.conf(其中包含指向/ etc / nginx / sites-available / default文件的包含指令)。
但是当发出https://myapp.com请求时,我的应用会抛出以下错误:
防伪系统的配置值为AntiforgeryOptions.Cookie.SecurePolicy = Always,但当前请求不是SSL请求。
谷歌浏览器显示:
ERR_TOO_MANY_REDIRECTS
如果我注释掉以下代码:
//var options = new RewriteOptions().AddRedirectToHttps();
//app.UseRewriter(options);
错误消失,我的应用程序按预期工作。
请解释一下这个问题。我如何配置nginx,以便我的网络应用程序仍然可以工作,而无需注释掉上述代码?或者我应该摆脱程序化重定向,如果nginx已配置为将http重定向到https?
答案 0 :(得分:0)
谷歌浏览器显示:
ERR_TOO_MANY_REDIRECTS
从nginx配置中可以看出,它通过http协议将用户请求转发到后端服务器,而不是https。您可能知道,这是一种常见的做法,您的后端服务器必须位于专用网络中(例如https://www.digitalocean.com/community/tutorials/how-to-set-up-nginx-load-balancing-with-ssl-termination)。
proxy_pass http://localhost:5000;
但是你的后端服务器总是返回302重定向,因为
options.Filters.Add(new RequireHttpsAttribute());
// this filter redirects to https
和
var options = new RewriteOptions().AddRedirectToHttps();
app.UseRewriter(options);
// this rewrite redirects to https
因此,您有两个位置,您的后端服务器将返回302重定向。
这样,当您打开https://myapp.com时,nginx会通过http协议将您的请求转发给您的后端服务器,它会以302重定向到https协议(https://myapp.com)进行响应,并且循环重复。
1)Nginx在通过https收到用户请求后,将X-Forwarded-For
和X-Forwarded-Proto
标头发送到后端服务器。
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
✓你的nginx配置有
2)Asp Core使用这些标题
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
✓您的应用使用标题
3)RewriteOptions().AddRedirectToHttps()
部分追踪app.UseForwardedHeaders
部分
❌这就是你的应用程序停留在重定向循环中的原因
由于mvc过滤器是在中间件之后应用的,如果您的重写重定向被注释掉,options.Filters.Add(new RequireHttpsAttribute())
不会抱怨https。
但是如果同时删除app.UseForwardedHeaders
和重写重定向,你会得到另一个重定向循环,但现在它是由mvc过滤器引起的。
并且,如果你删除了过滤器,反伪造系统会通过抛出The antiforgery system has the configuration value AntiforgeryOptions.Cookie.SecurePolicy = Always, but the current request is not an SSL request.
异常开始抱怨cookie。