ASP.NET Core WebAPI中使用Jwt实现用户认证

生成Jwt Token

AuthController

using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using WebAPI.Models;

namespace WebAPI.Controllers
{
    [Produces("application/json")]
    [Route("api/v1/[controller]")]
    public class AuthController : Controller
    {
        private readonly IConfiguration _configuration;

        public AuthController(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        /// <summary>
        /// login
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost]
        public IActionResult RequestToken([FromBody] TokenRequest request)
        {
            string username = request.Username;
            string password = request.Password;

            if (AuthenticationMiddleware.ValidateDomainUser(username, password))
            {
                // push the user’s name into a claim, so we can identify the user later on.
                var claims = new[]
                {
                   new Claim(ClaimTypes.Name, request.Username)
               };
                //sign the token using a secret key.This secret will be shared between your API and anything that needs to check that the token is legit.
                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["SecurityKey"]));
                var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                //.NET Core’s JwtSecurityToken class takes on the heavy lifting and actually creates the token.
                /**
                 * Claims (Payload)
                    Claims 部分包含了一些跟这个 token 有关的重要信息。 JWT 标准规定了一些字段,下面节选一些字段:

                    iss: The issuer of the token,token 是给谁的
                    sub: The subject of the token,token 主题
                    exp: Expiration Time。 token 过期时间,Unix 时间戳格式
                    iat: Issued At。 token 创建时间, Unix 时间戳格式
                    jti: JWT ID。针对当前 token 的唯一标识
                    除了规定的字段外,可以包含其他任何 JSON 兼容的字段。
                 * */
                var token = new JwtSecurityToken(
                    issuer: "yourdomain.com",
                    audience: "yourdomain.com",
                    claims: claims,
                    expires: DateTime.Now.AddMinutes(30),
                    signingCredentials: creds);

                var accessToken = new JwtSecurityTokenHandler().WriteToken(token);

                var response = new {

                    username = username,
                    access_token = accessToken,
                    expires_in = 1800
                };

                return Ok(response);

                //return Ok(new
                //{
                //    token = new JwtSecurityTokenHandler().WriteToken(token)
                //});
            }
            else
            {
                return BadRequest("Could not verify username and password");
            }
            
        }
    }

    public class TokenRequest
    {
        public string Username { get; set; }
        public string Password { get; set; }
    }
}

在appsettings.json中添加

"SecurityKey": "234d#;pvsfa88*sdfaf377f6d&f£$$£$sfxvgdf%"

使用jwt验证

在Startup.cs中

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System.Text;

namespace WebAPI
{
    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)
        {
            //添加jwt验证:
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options=> {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = true,//是否验证Issuer
                        ValidateAudience = true,//是否验证Audience
                        ValidateLifetime = true,//是否验证失效时间
                        ValidateIssuerSigningKey = true,//是否验证SecurityKey
                        ValidAudience = "yourdomain.com",//Audience
                        ValidIssuer = "yourdomain.com",//Issuer,这两项和前面签发jwt的设置一致
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["SecurityKey"]))//拿到SecurityKey
                    };
                });
            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseAuthentication();//注意添加这一句,启用验证
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvc();
        }
    }
}

如果你的前后端涉及到跨域,还需在Startup.cs中加上

public void ConfigureServices(IServiceCollection services){
    
    //其他

    services.AddCors(options =>
            {
                options.AddPolicy("cors", builder =>
                {
                    //builder.WithOrigins("http://a.example.com", "http://c.example.com") 
                    builder.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials();
                });
            });
            //"http://a.example.com", "http://c.example.com" 代表着允许访问的域,就好像给这个域开放了一个权限,允许访问的权限,可以写多个逗号分隔
            //AllowAnyMethod允许跨域策略允许所有的方法:GET/POST/PUT/DELETE 等方法  如果进行限制需要 AllowAnyMethod("GET","POST") 这样来进行访问方法的限制
            //AllowAnyHeader允许任何的Header头部标题    有关头部标题如果不设置就不会进行限制
            //AllowAnyOrigin 允许任何来源
            //AllowCredentials 设置凭据来源

    services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env){

    app.UseAuthentication();
    app.UseCors("cors"); // 加上这一句
    app.UseMvc();
}

设置超时时间

在appsettins.json中添加

"Expire_in": 10

AuthController中添加

int expires_in = int.Parse(_configuration["Expire_in"]);

完整AuthController代码

using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using WebAPI.Data;
using WebAPI.Models;

namespace WebAPI.Controllers
{
    [Produces("application/json")]
    [Route("api/v1/[controller]")]
    public class AuthController : Controller
    {
        private readonly IConfiguration _configuration;

        private readonly UserTokenContext _context;

        public AuthController(IConfiguration configuration, UserTokenContext context)
        {
            _configuration = configuration;
            _context = context;
        }

        //public UserController(UserToken context)
        //{
        //    _context = context;
        //}

        /// <summary>
        /// login
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost]
        public IActionResult RequestToken([FromBody] TokenRequest request)
        {
            string username = request.Username;
            string password = request.Password;
            
            //这里主要是用来验证用户名密码合不合法的,不重要,主要看下面if里面的就行
            if (AuthenticationMiddleware.ValidateDomainUser(username, password))
            {
                // push the user’s name into a claim, so we can identify the user later on.
                var claims = new[]
                {
                   new Claim(ClaimTypes.Name, request.Username)
               };
                //sign the token using a secret key.This secret will be shared between your API and anything that needs to check that the token is legit.
                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["SecurityKey"]));
                var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                //.NET Core’s JwtSecurityToken class takes on the heavy lifting and actually creates the token.
                /**
                 * Claims (Payload)
                    Claims 部分包含了一些跟这个 token 有关的重要信息。 JWT 标准规定了一些字段,下面节选一些字段:

                    iss: The issuer of the token,token 是给谁的
                    sub: The subject of the token,token 主题
                    exp: Expiration Time。 token 过期时间,Unix 时间戳格式
                    iat: Issued At。 token 创建时间, Unix 时间戳格式
                    jti: JWT ID。针对当前 token 的唯一标识
                    除了规定的字段外,可以包含其他任何 JSON 兼容的字段。
                 * */

                int expires_in = int.Parse(_configuration["Expire_in"]);

                var token = new JwtSecurityToken(
                    issuer: "yourdomain.com",
                    audience: "yourdomain.com",
                    claims: claims,
                    expires: DateTime.Now.AddMinutes(expires_in),
                    signingCredentials: creds);

                var accessToken = new JwtSecurityTokenHandler().WriteToken(token);

                UserToken userToken = new UserToken();


                //var user = _context.User
                    //.FirstOrDefault(m => m.UserName == username);

                //userToken.Id = Guid.NewGuid();
                //userToken.UserId = user.UserId;
                //userToken.Token = accessToken;
                //userToken.LoginTime = DateTime.Now;

                //_context.UserToken.Add(userToken);
                //_context.SaveChanges();

                var response = new {
                    username,
                    access_token = accessToken,
                    expires_in = expires_in
                };

                return Ok(response);
            }
            else
            {
                return BadRequest("Could not verify username or password");
            }
            
        }

        [HttpGet("checklogin")]
        [Authorize]
        public IActionResult CheckLogin() {
            return Ok();
        }

        [HttpGet("logout")]
        [Authorize]
        public IActionResult Logout()
        {
            return Ok();
        }
    }

    public class TokenRequest
    {
        public string Username { get; set; }
        public string Password { get; set; }
    }
}

测试

Postman

http://localhost:3019/api/v1/auth Post请求

请求体,放在Postman的Body中

{
    "username":"shajia_shan",
    "password":"123456"
}

看一下接口拦截

先写一个UserController

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace WebAPI.Controllers
{
    [Route("api/v1/[controller]")]
    [ApiController]
    public class UserController : ControllerBase
    {
        // GET api/values
        [HttpGet]
        [Authorize]//添加Authorize标签,可以加在方法上,也可以加在类上
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }
        // GET api/values/5
        [HttpGet("{id}")]
        public string Get(int id)
        {
            return "value";
        }
    }
}

打开Postman

http://localhost:3019/api/v1/user Get请求

Authorization选择Bearer Token,填入刚刚登录接口返回的access_token

返回200表示认证成功, 如果token超时或者没有填,接口返回401。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值