ASP.NET核心与Dapper和VS 2017使用JWT身份验证WEB API在Angular2

介绍

我试图在Web API中实现JWT Auth。我想在Angular 2客户端应用程序中使用Web API。但是在互联网上搜索时,我没有找到任何正确的解决方案来解决我的Project架构设置问题最后,我能够获得如何解决这个问题的实际步骤,这可以帮助您节省时间来检查此解决方案中的大量内容。所以这是下面的详细说明。

源代码链接:https//github.com/rajeshdas85/JwtAuthentication

  1. 使用JWT身份验证的ASP.NET Core中的Web API项目解决方案

  2. Angular2 / 4用于客户端应用程序

请参阅下面的项目结构:

Project_Architecture

背景

步骤1

创建ASP.NET Core Web API项目

  1. 打开“Visual Studio 2017” - >转到“文件”菜单 - >新建 - >项目

  2. 选择项目模板。

    此搜索

  3. 右键单击Solution Explorer - > Add - > New Project-> Class Library。

    图像2

Fitness.JWT.API项目说明

我想解释一下用于启用Jwt身份验证的项目源代码的突出显示部分。

图像3

使用代码

startup.cs

配置secretkey,允许跨源并应用使用策略身份验证。

隐藏   收缩    复制代码

//
 public IConfigurationRoot Configuration { get; }        //SecretKey  for Authentication
        private const string SecretKey = "ABCneedtogetthisfromenvironmentXYZ";        private readonly SymmetricSecurityKey _signingKey = 
              new SymmetricSecurityKey(Encoding.ASCII.GetBytes(SecretKey));        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {            // Add framework services.
            // services.AddMvc();
            // Add framework services.
            // Add framework services.
            services.AddCors(options =>
            {
                options.AddPolicy("CorsPolicy",//Allow Cross origin
                    builder => builder.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials());
            });

            services.AddOptions();            // Make authentication compulsory across the board (i.e. shut
            // down EVERYTHING unless explicitly opened up).
            services.AddMvc(config =>
            {                var policy = new AuthorizationPolicyBuilder()
                                 .RequireAuthenticatedUser()
                                 .Build();
                config.Filters.Add(new AuthorizeFilter(policy));
            });            // Use policy auth.
            services.AddAuthorization(options =>
            {
                options.AddPolicy("FitnessJWT",
                                  policy => policy.RequireClaim("FitnessJWT", "FitnessUser"));
            });            // Get options from app settings
            var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));            // Configure JwtIssuerOptions
            services.Configure<JwtIssuerOptions>(options =>
            {
                options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
                options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
                options.SigningCredentials = new SigningCredentials
                                    (_signingKey, SecurityAlgorithms.HmacSha256);
            });
        }//

JwtIssuerOptions.cs

这是类文件,负责在服务器中创建Auth唯一票证。

隐藏   收缩    复制代码

//
  public class JwtIssuerOptions
{    /// <summary>    /// "iss" (Issuer) Claim    /// </summary>    /// <remarks>The "iss" (issuer) claim identifies the principal that issued the    ///   JWT.  The processing of this claim is generally application specific.    ///   The "iss" value is a case-sensitive string containing a StringOrURI    ///   value.  Use of this claim is OPTIONAL.</remarks>    public string Issuer { get; set; }    /// <summary>    /// "sub" (Subject) Claim    /// </summary>    /// <remarks> The "sub" (subject) claim identifies the principal that is the    ///   subject of the JWT.  The claims in a JWT are normally statements    ///   about the subject.  The subject value MUST either be scoped to be    ///   locally unique in the context of the issuer or be globally unique.    ///   The processing of this claim is generally application specific.  The    ///   "sub" value is a case-sensitive string containing a StringOrURI    ///   value.  Use of this claim is OPTIONAL.</remarks>    public string Subject { get; set; }    /// <summary>    /// "aud" (Audience) Claim    /// </summary>    /// <remarks>The "aud" (audience) claim identifies the recipients that the JWT is    ///   intended for.  Each principal intended to process the JWT MUST    ///   identify itself with a value in the audience claim.  If the principal    ///   processing the claim does not identify itself with a value in the    ///   "aud" claim when this claim is present, then the JWT MUST be    ///   rejected.  In the general case, the "aud" value is an array of case-    ///   sensitive strings, each containing a StringOrURI value.  In the    ///   special case when the JWT has one audience, the "aud" value MAY be a    ///   single case-sensitive string containing a StringOrURI value.  The    ///   interpretation of audience values is generally application specific.    ///   Use of this claim is OPTIONAL.</remarks>    public string Audience { get; set; }    /// <summary>    /// "nbf" (Not Before) Claim (default is UTC NOW)    /// </summary>    /// <remarks>The "nbf" (not before) claim identifies the time before which the JWT    ///   MUST NOT be accepted for processing.  The processing of the "nbf"    ///   claim requires that the current date/time MUST be after or equal to    ///   the not-before date/time listed in the "nbf" claim.  Implementers MAY    ///   provide for some small leeway, usually no more than a few minutes, to    ///   account for clock skew.  Its value MUST be a number containing a    ///   NumericDate value.  Use of this claim is OPTIONAL.</remarks>    public DateTime NotBefore => DateTime.UtcNow;    /// <summary>    /// "iat" (Issued At) Claim (default is UTC NOW)    /// </summary>    /// <remarks>The "iat" (issued at) claim identifies the time at which the JWT was    ///   issued.  This claim can be used to determine the age of the JWT.  Its    ///   value MUST be a number containing a NumericDate value.  Use of this    ///   claim is OPTIONAL.</remarks>    public DateTime IssuedAt => DateTime.UtcNow;    /// <summary>    /// Set the timespan the token will be valid for (default is 3 min/180 seconds)    /// </summary>    public TimeSpan ValidFor { get; set; } = TimeSpan.FromMinutes(1);    /// <summary>    /// "exp" (Expiration Time) Claim (returns IssuedAt + ValidFor)    /// </summary>    /// <remarks>The "exp" (expiration time) claim identifies the expiration time on    ///   or after which the JWT MUST NOT be accepted for processing.  The    ///   processing of the "exp" claim requires that the current date/time    ///   MUST be before the expiration date/time listed in the "exp" claim.    ///   Implementers MAY provide for some small leeway, usually no more than    ///   a few minutes, to account for clock skew.  Its value MUST be a number    ///   containing a NumericDate value.  Use of this claim is OPTIONAL.</remarks>    public DateTime Expiration => IssuedAt.Add(ValidFor);    /// <summary>    /// "jti" (JWT ID) Claim (default ID is a GUID)    /// </summary>    /// <remarks>The "jti" (JWT ID) claim provides a unique identifier for the JWT.    ///   The identifier value MUST be assigned in a manner that ensures that    ///   there is a negligible probability that the same value will be    ///   accidentally assigned to a different data object; if the application    ///   uses multiple issuers, collisions MUST be prevented among values    ///   produced by different issuers as well.  The "jti" claim can be used    ///   to prevent the JWT from being replayed.  The "jti" value is a case-    ///   sensitive string.  Use of this claim is OPTIONAL.</remarks>    public Func<Task<string>> JtiGenerator =>
      () => Task.FromResult(Guid.NewGuid().ToString());    /// <summary>    /// The signing key to use when generating tokens.    /// </summary>    public SigningCredentials SigningCredentials { get; set; }
}//

JwtController.cs

它是匿名用户将登录的控制器,它创建JWT安全令牌并对其进行编码,并作为具有策略的响应发送回客户端。

identity.FindFirst( “FitnessJWT”)

请参阅以下代码:

隐藏   收缩    复制代码

[HttpPost]
       [AllowAnonymous]       public async Task<IActionResult> Get([FromBody] ApplicationUser applicationUser)
       {           var identity = await GetClaimsIdentity(applicationUser);           if (identity == null)
           {
               _logger.LogInformation($"Invalid username ({applicationUser.UserName})
                                      or password ({applicationUser.Password})");               return BadRequest("Invalid credentials");
           }           var claims = new[]
           {       new Claim(JwtRegisteredClaimNames.Sub, applicationUser.UserName),       new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),       new Claim(JwtRegisteredClaimNames.Iat,
           ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
       identity.FindFirst("FitnessJWT")
     };           // Create the JWT security token and encode it.
           var jwt = new JwtSecurityToken(
               issuer: _jwtOptions.Issuer,
               audience: _jwtOptions.Audience,
               claims: claims,
               notBefore: _jwtOptions.NotBefore,
               expires: _jwtOptions.Expiration,
               signingCredentials: _jwtOptions.SigningCredentials);           var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);           // Serialize and return the response
           var response = new
           {
               access_token = encodedJwt,
               expires_in = (int)_jwtOptions.ValidFor.TotalSeconds,
               State=1,
               expire_datetime= _jwtOptions.IssuedAt
           };           var json = JsonConvert.SerializeObject(response, _serializerSettings);           return new OkObjectResult(json);
       }

JwtAuthTestController.cs

这个控制器我定义了策略,所以当用户请求控制器时,它必须与策略和密钥匹配,然后响应将返回给客户端。[Authorize(Policy = "FitnessJWT")]

隐藏   复制代码

[HttpGet("[action]")]
      [Authorize(Policy = "FitnessJWT")]      public IActionResult WeatherForecasts()
      {          var rng = new Random();

          List<WeatherForecast> lstWeatherForeCast = new List<WeatherForecast>();          for (int i = 0; i < 5; i++)
          {
              WeatherForecast obj = new WeatherForecast();
              obj.DateFormatted = DateTime.Now.AddDays(i).ToString("d");
              obj.TemperatureC = rng.Next(-20, 55);
              obj.Summary = Summaries[rng.Next(Summaries.Length)];
              lstWeatherForeCast.Add(obj);
          }          var response = new
          {
              access_token = lstWeatherForeCast,
              State = 1
          };          var json = JsonConvert.SerializeObject(response, _serializerSettings);          return new OkObjectResult(json);
      }

第2步:Angular2 / 4用于客户端应用程序

我想补充其中一个。我没有太多关注UI部分,但我试图从Angualar2 / 4应用程序实现JWT Auth。

Fitness.App.UI解决方案

login.component.ts

通过传递用户名和密码登录带有打字稿的模块:

隐藏   复制代码

import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from "../../../app/services/auth.service";
import { LoginModel } from "../../model/login.model";
@Component({
    selector: 'Fitness-Login',
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.css'],
    providers: [AuthService]
})
export class LoginComponent {
    loginModel = new LoginModel();
    constructor(private router: Router, private authService: AuthService) {
    }
    login() {        this.authService.login(this.loginModel.userName, this.loginModel.password)
            .then(result => {                if (result.State == 1) {                    this.router.navigate(["/nav-menu"]);
                }                else {
                    alert(result.access_token);
                }
            });
    }
}
auth.service.ts

验证服务,验证凭据并重定向到主页。

隐藏   收缩    复制代码

login(userName: string, password: string): Promise<ResponseResult> {    let data = {        "userName": userName,        "password": password
    }    let headers = new Headers({ 'Content-Type': 'application/json' });    let applicationUser = JSON.stringify(data);    let options = new RequestOptions({ headers: headers });    if (this.checkLogin()) {        return this.authPost(this.localUrl + '/api/Jwt', applicationUser, options);
    }    else {        return this.http.post(this.localUrl + '/api/Jwt', applicationUser, options).toPromise()
            .then(
            response => {                let result = response.json() as ResponseResult;                if (result.State == 1) {                    let json = result.access_token as any;
                    localStorage.setItem(this.tokeyKey, json);
                    localStorage.setItem(this.tokeyExpKey, result.expire_datetime);                    this.sg['isUserExist'] = true;
                }                return result;
            }
            )
            .catch(this.handleError);
    }
}
app.module.client.ts

{ provide: 'ORIGIN_URL', useValue: 'http://localhost:57323' },JWT WEB API上的路径。

您需要根据计算机URL更改本地主机API。

隐藏   复制代码

  @NgModule({
    bootstrap: sharedConfig.bootstrap,
    declarations: sharedConfig.declarations,
    imports: [
        BrowserModule,
        FormsModule,
        HttpModule,
        ...sharedConfig.imports
    ],
    providers: [        //{ provide: 'ORIGIN_URL', useValue: location.origin },
        { provide: 'ORIGIN_URL', useValue: 'http://localhost:57323' },
        AuthService, AuthGuard, SimpleGlobal
    ]
})
export class AppModule {
}

要运行应用程序,您需要将项目设置如下:

使用多个启动项目运行解决方案。

然后在两个选项卡的浏览器中,客户端应用程序和Web API服务都将启动。

图像4

应用程序的输出在下面

image6

图像5

用户名:测试和密码:测试

然后,它将重定向到导航菜单页面,如下所示:

image7

源代码

下载源代码

合作伙伴

网站备案:豫ICP备15023476号-1 唯特科技