1

我需要支持兩種認證方式在ASP.NET核2.0 MVC應用程序:多authenticaion方案2.0

  1. AddIdentityServerAuthentication
  2. AddOpenIdConnect

這是非常易於在ASP.NET Core 1.0版本。但在版本2.0版本語法已更改。這是我的代碼:

services.AddAuthentication(o => 
    { 
     o.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; 
     o.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; 
     o.DefaultAuthenticateScheme = OpenIdConnectDefaults.AuthenticationScheme; 
    }).AddIdentityServerAuthentication(options => 
    { 
     options.Authority = PlatformConfiguration.IdentityServerUri; 
     options.RequireHttpsMetadata = false; 
     options.SaveToken = true; 
     options.ApiSecret = "somesecret"; 
     options.ApiName = "some_api"; 
    }) 
    .AddCookie() 
    .AddOpenIdConnect(o => 
    { 
     o.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; 
     o.Authority = PlatformConfiguration.IdentityServerUri; 
     o.RequireHttpsMetadata = false; 
     o.ClientId = "some_viewer"; 
     o.UseTokenLifetime = true; 
     o.ResponseType = "id_token token"; 
     o.Scope.Add("openid"); 
     o.Scope.Add("roles"); 
     o.Scope.Add("profile"); 
     o.SaveTokens = true; 
     o.TokenValidationParameters = new TokenValidationParameters 
     { 
      NameClaimType = JwtClaimTypes.Name, 
      RoleClaimType = JwtClaimTypes.Role 
     }; 
    }); 

services.AddAuthorization(); 

但是這樣,承載認證不起作用。由於默認方案:DefaultChallengeScheme,DefaultAuthenticateScheme
如何定義多種認證方案?

回答

2

我添加屬性

[Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme + "," + OpenIdConnectDefaults.AuthenticationScheme)] 

現在我有兩個身份驗證方案。

更靈活的解決方案在啓動使用此代碼:

if (UseAuthorization) 
{ 
    var policy = new AuthorizationPolicyBuilder(IdentityServerAuthenticationDefaults.AuthenticationScheme, OpenIdConnectDefaults.AuthenticationScheme) 
     .RequireAuthenticatedUser() 
     .Build(); 

    options.Filters.Add(new AuthorizeFilter(policy)); 
} 
1

這裏是我以前在ASP.NET 2.0身份驗證使用JWT令牌網頁

你可以找到的語法我的例子即使它不包括您的所有需求,我也希望它能幫助您。

ASP網核心

第一步是編寫配置JWT身份驗證方法:

// Configure authentication with JWT (Json Web Token). 
public void ConfigureJwtAuthService(IServiceCollection services) 
{ 
    // Enable the use of an [Authorize(AuthenticationSchemes = 
    // JwtBearerDefaults.AuthenticationScheme)] 
    // attribute on methods and classes to protect. 
    services.AddAuthentication().AddJwtBearer(cfg => 
    { 
    cfg.RequireHttpsMetadata = false; 
    cfg.SaveToken = true; 
    cfg.TokenValidationParameters = new TokenValidationParameters() 
    { 
     IssuerSigningKey = JwtController.SecurityKey, 
     ValidAudience = JwtController.Audience, 
     ValidIssuer = JwtController.Issuer, 
     // When receiving a token, check that we've signed it. 
     ValidateIssuerSigningKey = true, 
     // When receiving a token, check that it is still valid. 
     ValidateLifetime = true, 
     // This defines the maximum allowable clock skew when validating 
     // the lifetime. As we're creating the tokens locally and validating 
     // them on the same machines which should have synchronised time, 
     // this can be set to zero. 
     ClockSkew = TimeSpan.FromMinutes(0) 
    }; 
    }); 
} 

現在ConfigureServices()內的Startup.cs方法,我們可以請撥打ConfigureJwtAuthService()方法來配置Jwt身份驗證。

這是完整的Startup.cs

using System; 
using Autofac; 
using ExpertCodeBlogWebApp.Controllers; 
using ExpertCodeBlogWebApp.Domain; 
using ExpertCodeBlogWebApp.Domain.Interfaces; 
using Microsoft.AspNetCore.Builder; 
using Microsoft.AspNetCore.Hosting; 
using Microsoft.AspNetCore.SpaServices.Webpack; 
using Microsoft.Extensions.Configuration; 
using Microsoft.Extensions.DependencyInjection; 

using Microsoft.IdentityModel.Tokens; 

namespace ExpertCodeBlogWebApp 
{ 
    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 IServiceProvider ConfigureServices(IServiceCollection services) 
    { 
    services.AddMvc(); 

    // Configure jwt autenticazione 
    ConfigureJwtAuthService(services); 

    // Repositories 
    services.AddScoped<IUserRepository, UserRepository>(); 

    // Create the Autofac container builder for dependency injection 
    var builder = new ContainerBuilder(); 

    // Add any Autofac modules or registrations. 
    builder.RegisterModule(new AutofacModule()); 

    // Return ServiceProvider 
    var serviceProvider = services.BuildServiceProvider(); 
    return serviceProvider; 
    } 

    // Configure authentication with JWT (Json Web Token). 
    public void ConfigureJwtAuthService(IServiceCollection services) 
    { 
    // Enable the use of an [Authorize(AuthenticationSchemes = 
    // JwtBearerDefaults.AuthenticationScheme)] 
    // attribute on methods and classes to protect. 
    services.AddAuthentication().AddJwtBearer(cfg => 
    { 
     cfg.RequireHttpsMetadata = false; 
     cfg.SaveToken = true; 

     cfg.TokenValidationParameters = new TokenValidationParameters() 
     { 
     IssuerSigningKey = JwtController.SecurityKey, 
     ValidAudience = JwtController.Audience, 
     ValidIssuer = JwtController.Issuer, 
     // When receiving a token, check that we've signed it. 
     ValidateIssuerSigningKey = true, 
     // When receiving a token, check that it is still valid. 
     ValidateLifetime = true, 
     // This defines the maximum allowable clock skew when validating 
     // the lifetime. 
     // As we're creating the tokens locally and validating them on the 
     // same machines which should have synchronised time, this can be 
     // set to zero. 
     ClockSkew = TimeSpan.FromMinutes(0) 
     }; 
    }); 
    } 

    // 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(); 
     app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions 
     { 
     HotModuleReplacement = true 
     }); 
    } 
    else 
    { 
     app.UseExceptionHandler("/Home/Error"); 
    } 

    app.UseStaticFiles(); 

    app.UseMvc(routes => 
    { 
     routes.MapRoute(
     name: "default", 
     template: "{controller=Home}/{action=Index}/{id?}"); 

     routes.MapSpaFallbackRoute(
     name: "spa-fallback", 
     defaults: new { controller = "Home", action = "Index" }); 
     }); 
    } 
    } 

    // For dependency injection. 
    public class AutofacModule : Module 
    { 
    // Dependency Injection with Autofact 
    protected override void Load(ContainerBuilder builder) 
    { 
     builder.RegisterType<UserRepository>().As<IUserRepository>() 
     .SingleInstance(); 
    } 
    } 
} 

JwtController.cs

using System; 
using System.IdentityModel.Tokens.Jwt; 
using System.Security.Claims; 
using System.Security.Principal; 
using System.Text; 
using System.Threading.Tasks; 
using AutoMapper; 
using ExpertCodeBlogWebApp.Domain; 
using ExpertCodeBlogWebApp.Domain.Interfaces; 
using ExpertCodeBlogWebApp.Domain.Models; 
using ExpertCodeBlogWebApp.ViewModels; 
using Microsoft.AspNetCore.Mvc; 
using Microsoft.Extensions.Logging; 
using Microsoft.IdentityModel.Tokens; 
using Newtonsoft.Json; 

namespace ExpertCodeBlogWebApp.Controllers 
{ 

[Route("api/[controller]")] 
public class JwtController : Controller 
{ 
    #region Private Members 
    // JWT-related members 
    private TimeSpan TokenExpiration; 
    private SigningCredentials SigningCredentials; 
    // EF and Identity members, available through DI 
    private MyDbContext DbContext; 
    private IUserRepository _userRepository; 
    private readonly ILogger _logger; 
    #endregion Private Members 

    #region Static Members 
    private static readonly string PrivateKey = "my_PrivateKey"; 
    public static readonly SymmetricSecurityKey SecurityKey = 
    new SymmetricSecurityKey(Encoding.ASCII.GetBytes(PrivateKey)); 
    public static readonly string Issuer = "my_Issuer"; 
    public static readonly string Audience = "my_Audience"; 
    #endregion Static Members 

    #region Constructor 
    // I have used Autofac in the Startup.cs for dependency injection) 
    public JwtController(
    MyDbContext dbContext, 
    IUserRepository userRepository, 
    ILogger<JwtController> logger) 
    { 
    _logger = logger; 
    _userRepository = userRepository; 
    // Instantiate JWT-related members 
    TokenExpiration = TimeSpan.FromMinutes(10); 
    SigningCredentials = new SigningCredentials(SecurityKey, 
     SecurityAlgorithms.HmacSha256); 
    // Instantiate through Dependency Injection with Autofact 
    DbContext = dbContext; 
    } 
    #endregion Constructor 

    #region Public Methods 
    // Manages the request for a new authentication or the refresh of an 
    // already established one 
    [HttpPost("token")] 
    public async Task<IActionResult> 
    Authentication([FromBody]JwtRequestViewModel jwt) 
    { 
    if (ModelState.IsValid) 
    { 
     string grantType = jwt.GrantType; 
     if (grantType == "password") 
     { 
     string userName = jwt.UserName; 
     string password = jwt.Password; 

     // Password check required 
     var user = await 
      _userRepository.GetUserInfoWithCheckPwd(userName, password); 

     // Check if user is expired (check the ExpireDate property) 
     if (UserExpired(user)) 
      return BadRequest($"Account of {user.Name} expired!"); 

     if (UserEnabled(user)) 
      return await GenerateToken(user); 
     else 
      return BadRequest("User name or password invalid."); 
     } 
    } 
    else if (grantType == "refresh_token") 
    { 
     string userName = jwt.UserName; 

     // Refresh token (no password check required) 
     var user = await _userRepository.GetUserInfoByName(userName); 

     // Check if user is expired (check the ExpireDate property) 
     if (UserExpired(user)) 
     return BadRequest($"Account of {user.Name} expired!"); 

     string token = jwt.Token; 
     if (token == user.Token) 
     { 
     // Generate token and send it via a json-formatted string 
     return await GenerateToken(user); 
     } 
     else 
     { 
     return BadRequest("User token invalid."); 
     } 
    } 
    else 
     return BadRequest("Authentication type invalid."); 
    } 
    else 
    return BadRequest("Request invalid."); 
    } 
    #endregion Public Methods 

    #region Private Methods 
    private bool UserExpired(Users utente) 
    { 
    if (utente != null) 
     return utente.ExpireDate.CompareTo(DateTime.Now) < 0; 
    return true; 
    } 

    private bool UserEnabled(Users utente) 
    { 
    if (utente != null) 
     return utente.Enabled == true; 
    return false; 
    } 

    private JsonSerializerSettings DefaultJsonSettings 
    { 
    get 
    { 
     return new JsonSerializerSettings() 
     { 
     Formatting = Formatting.Indented 
     }; 
    } 
    } 

    private async Task<IActionResult> GenerateToken(Users user) 
    { 
    try 
    { 
     if (user != null) 
     { 
     var handler = new JwtSecurityTokenHandler(); 
     DateTime newTokenExpiration = DateTime.Now.Add(TokenExpiration); 

     ClaimsIdentity identity = new ClaimsIdentity(
      new GenericIdentity(user.Name, "TokenAuth"), 
      new[] { new Claim("ID", user.Id.ToString())} 
     ); 

     var securityToken = handler.CreateToken(new SecurityTokenDescriptor 
     { 
      Issuer = JwtController.Issuer, 
      Audience = JwtController.Audience, 
      SigningCredentials = SigningCredentials, 
      Subject = identity, 
      Expires = newTokenExpiration 
     }); 
     string encodedToken = handler.WriteToken(securityToken); 

     // Update token data on database 
     await _userRepository.UpdateTokenData(user.Name, encodedToken, 
      newTokenExpiration); 
     // Build the json response 
     // (I use Automapper to maps an object into another object) 
     var jwtResponse = Mapper.Map<JwtResponseViewModel>(user); 
     jwtResponse.AccessToken = encodedToken; 
     jwtResponse.Expiration = (int)TokenExpiration.TotalSeconds; 
     return Ok(jwtResponse); 
     } 
     return NotFound(); 
     } 
     catch(Exception e) 
     { 
     return BadRequest(e.Message); 
     } 
    } 
    #endregion 
    } 
} 

在我的項目,我使用的角度。對於由角呼叫JwtController方法:

login(userName: string, password: string) 
{ 
    return this.getLoginEndpoint(userName, password) 
    .map((response: Response) => this.processLoginResponse(response)); 
} 

getLoginEndpoint(userName: string, password: string): Observable<Response> 
{ 
    // Body 
    // JwtRequest is a model class that I use to send info to the controller 
    let jwt = new JwtRequest(); 
    jwt.GrantType = "password"; 
    jwt.UserName = userName; 
    jwt.Password = password; 
    jwt.ClientId = "my_Issuer"; 
    // Post requiest (I use getAuthHeader that attach to the header the 
    // authentication token, but it can also be omitted because it is ignored 
    // by the JwtController 
    return this.http.post(this.loginUrl, JSON.stringify(jwt), 
    this.getAuthHeader(true)) 
} 

protected getAuthHeader(includeJsonContentType?: boolean): RequestOptions 
{ 
    // Hera I use this.authService.accessToken that is a my service where 
    // I have store the token received from the server 
    let headers = new Headers({ 
    'Authorization': 'Bearer ' + this.authService.accessToken }); 

    if (includeJsonContentType) 
    headers.append("Content-Type", "application/json"); 

    headers.append("Accept", `application/vnd.iman.v01+json, 
    application/json, text/plain, */*`); 
    headers.append("App-Version", "01"); 

    return new RequestOptions({ headers: headers }); 
} 

private processLoginResponse(response: Response) 
{ 
    // process the response.. 
} 

在您希望只通過身份驗證的用戶可訪問的(不是你的JwtController,因爲它的方法必須由所有用戶訪問)控制器類(或方法),你可以設置:

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] 

從角調用需要認證的控制器的方法,你需要將令牌附加與getAuthHeader()方法的頭。

我希望這篇文章可以幫助你。

+0

這樣好多了,謝謝。 –

相關問題