Vue axios 前端 ASP.Net Core WebAPI 后台JWT Token 认证

Vue axios 前端 ASP.Net Core WebAPI 后台JWT Token 认证

1、ASP.Net Core WebAPI JWT Token 认证

ASP.Net Core Web API 应用程序。
控制器:

    [Route("[controller]/[action]")]
    [ApiController]
    public class AuthController : Controller
    {
        public AuthController(IAesSecurity aesSecurity, ITokenHelper tokenHelper, ISqLiteHelper sqLiteHelper)
        {
            AesSecurity = aesSecurity;
            TokenHelper = tokenHelper;
            SqLiteHelper = sqLiteHelper;   
        }

        private ISqLiteHelper SqLiteHelper { get; } // linqTodb sqlte 数据库访问
        private IAesSecurity AesSecurity { get; }//Aes加解密工具类
        private ITokenHelper TokenHelper { get; }//Token生成工具类
        //供Vue axios 获取Jwt Token
        public IActionResult GetToken(string username, string password, string sms)
        {
            //获取Token:密码登录或短信登录
            if (string.IsNullOrEmpty(username))
                return null;
            if (string.IsNullOrEmpty(password))
                return Ok(CheckSms(username, sms));
            return Ok(CheckPassword(username, password));
        }

        private TokenResult CheckPassword(string username, string password)
        {
            //用户名手机号,在数据库中加密存储
            var scMobile = AesSecurity.Encrypt(username);
            var scPass = AesSecurity.Md5($"{username}{password}");
            return TokenHelper.TokenByPass(scMobile, scPass);
        }

        private TokenResult CheckSms(string username, string sms)
        {
            var scMobile = AesSecurity.Encrypt(username);
            return TokenHelper.TokenBySms(scMobile, sms);
        }

       [TokenFilter]
       [Authorize]
        public IActionResult GetValue1(string id)
        { 
            //JWT Token授权测试
            return Ok(new ResultModel<string>
            {
                Code = 1,
                Data = "return Test GetValue1!",
                Message = "Test GetValue 1-" + id
            });
        }

      [TokenFilter]
        public IActionResult GetValue2(string id)
        {//普通测试
            return Ok(new ResultModel<string>
            {
                Code = 1,
                Data = "return Test GetValue 2 !",
                Message = "AllowAnonymous Test GetValue 2-" + id
            });

        }
    }

ResultModel

  public class ResultModel
    {
        /// <summary>
        ///     返回码
        /// </summary>
        public int Code { get; set; }

        /// <summary>
        ///     消息
        /// </summary>
        public string Message { get; set; }

        /// <summary>
        ///     关联地址
        /// </summary>
        public string Url { get; set; }
    }

    public class ResultModel<T> : ResultModel
    {
        /// <summary>
        ///     数据
        /// </summary>
        public virtual T Data { get; set; }
    }

    public class ResultArray<T> : ResultModel<IEnumerable<T>>
    {
    }

JwtConfig

    public class JwtConfig
    {
        /// <summary>
        ///     签发人
        /// </summary>
        public string Issuer { get; set; }
        /// <summary>
        ///     主题
        /// </summary>
        public string Subject { get; set; }

        /// <summary>
        ///     受众(接受者)
        /// </summary>
        public string Audience { get; set; }
        /// <summary>
        /// 多用户登录
        /// </summary>
        public bool MultipleLogin { get; set; }

        /// <summary>
        ///     过期时间:分钟
        /// </summary>
        public int ExpiresMinutes { get; set; }
       
        /// <summary>
        ///    密匙:HMACSHA256
        /// </summary>
        public string SecretKey { get; set; }
        /// <summary>
        /// 缓冲过期时间 默认5分钟 有效时间 = 过期时间 + 缓冲过期时间
        /// </summary>
        public int ClockSkew { get; set; }
        /// <summary>
        /// 无权限指定路由
        /// </summary>
        public string DeniedAction { get; set; }
        /// <summary>
        /// 错误指定路由
        /// </summary>
        public string ErrorAction { get; set; }

        /// <summary>
        /// 忽略验证的路由
        /// </summary>
        public List<string> IgnoreUrls { get; set; }


    }

ITokenHelper 、TokenHelper

  public interface ITokenHelper
    {
        TokenResult TokenByPass(string username, string password);
        TokenResult TokenBySms(string username, string sms);
    }

    public class TokenHelper : ITokenHelper
    {
        public const string Domain = "http://localhost:5000";

        private readonly IOptions<JwtConfig> options;
        private readonly ISqLiteHelper sqLiteHelper;

        public TokenHelper(IOptions<JwtConfig> options, ISqLiteHelper sqLiteHelper)
        {
            this.options = options;
            this.sqLiteHelper = sqLiteHelper;
        }

        public TokenResult TokenBySms(string username, string sms)
        {
            var claims = new List<Claim>();
            var audience = options.Value.Audience;
            var loginTime = DateTime.Now;
            using (var dc = new YysxProductDB(sqLiteHelper.Option))
            {
                var user = dc.Users.FirstOrDefault(f => f.ScMobile == username && f.CheckSms == sms);
                if (user != null)
                {
                    claims.Add(new Claim(ClaimTypes.Name, username));
                    //claims.Add(new Claim("ErrorAction", options.Value.ErrorAction));
                    //claims.Add(new Claim("DeniedAction", options.Value.DeniedAction));
                    user.LoginTime = loginTime;
                    user.ExpirationTime = loginTime.AddHours(options.Value.ExpiresMinutes);
                    dc.Update(user);
                    audience = options.Value.Audience; // $"{username}{loginTime.Ticks}";
                }
            }

            return CreateTokenString(claims, audience, loginTime);
        }

        public TokenResult TokenByPass(string username, string password)
        {
            var claims = new List<Claim>();
            var audience = options.Value.Audience;
            var loginTime = DateTime.Now;
            using (var dc = new YysxProductDB(sqLiteHelper.Option))
            {
                var user = dc.Users.FirstOrDefault(f => f.ScMobile == username && f.Password == password);
                if (user != null)
                {
                    claims.Add(new Claim(ClaimTypes.Name, username));
                    //claims.Add(new Claim("ErrorAction", options.Value.ErrorAction));
                    //claims.Add(new Claim("DeniedAction", options.Value.DeniedAction));
                    user.LoginTime = loginTime;
                    user.ExpirationTime = loginTime.AddHours(options.Value.ExpiresMinutes);
                    dc.Update(user);
                    audience = options.Value.Audience; // $"{username}{loginTime.Ticks}";
                }
            }

            return CreateTokenString(claims, audience, loginTime);
        }

        /// <summary>
        ///     生成token
        /// </summary>
        /// <param name="claims">List的 Claim对象</param>
        /// <param name="audience"></param>
        /// <param name="loginTime"></param>
        /// <returns></returns>
        private TokenResult CreateTokenString(List<Claim> claims, string audience, DateTime loginTime)
        {
            var secret = Encoding.UTF8.GetBytes(TestToken.Secret);
            var key = new SymmetricSecurityKey(secret);
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var token = new JwtSecurityToken(
                TestToken.Issurer,
                TestToken.Audience,
                claims,
                expires: loginTime.AddMinutes(30),
                signingCredentials: creds);
            var expires = loginTime.AddMinutes(options.Value.ExpiresMinutes);
            var s = new JwtSecurityTokenHandler().WriteToken(token);
            return new TokenResult {Token = s, Expires = expires};
        }
    }

Startup ConfigureServices

   public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<ISqLiteHelper, SqLiteHelper>();
            services.AddSingleton<IAesSecurity, AesSecurity>();
            services.AddTransient<ITokenHelper, TokenHelper>();
            //添加配置
            services.Configure<TokenConfig>(Configuration.GetSection("TokenConfig"));
                   
            //设置跨域中间件:读取 appsetting.json的 AllowedHosts
            //否则axios 跨域访问时会出现两次请求,第一次尝试跨域options Method,通过后再请求Get Method。options 不能通过认证,导致get无法继续访问。           
            services.AddCors(options =>
            {
                // CorsPolicy 是自訂的 Policy 名稱
                options.AddPolicy("CorsPolicy", policy =>
                {
                    policy.SetPreflightMaxAge(TimeSpan.FromSeconds(1800L));//update by jason
                    var origins = Configuration.GetSection("AllowedHosts").Get<string[]>();
                    if (origins == null || origins.Contains("*"))
                    {
                        policy.AllowAnyOrigin()
                            .AllowAnyHeader()
                            .AllowAnyMethod();
                    }
                    else
                    {
                        policy.WithOrigins(origins)
                            .AllowAnyHeader()
                            .AllowAnyMethod();
                    }

                });
            });

            //配置认证服务
            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(o =>
            {
                o.TokenValidationParameters = new TokenValidationParameters
                {
                    //是否验证发行人
                    ValidateIssuer = true,
                    ValidIssuer = TestToken.Issurer,//发行人
                    //是否验证受众人
                    ValidateAudience = true,
                    ValidAudience = TestToken.Audience,//受众人
                    //是否验证密钥
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(TestToken.Secret)),

                    ValidateLifetime = true, //验证生命周期
                    RequireExpirationTime = true, //过期时间
                };
            });

            services.AddControllers();
        }

Startup Configure

      public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment()) app.UseDeveloperExceptionPage();
            app.UseHttpsRedirection();
            app.UseRouting();
            //0、启用跨域中间件
            app.UseCors("CorsPolicy");
            //1.先开启认证
            app.UseAuthentication();
            //2.再开启授权
            app.UseAuthorization();
            app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
        }

appsetting.json 配置

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",

  "JwtConfig": {
    "Issuer": "eyysx.net", //签发人
    "Subject": null, //主题
    "Audience": "Audience", //受众(接受者)
    "MultipleLogin": false,
    "ExpiresMinutes": 20, //过期时间:分钟
    "IssuedAt": null, //签发时间
    "SecretKey": "MIGfMA0GCSqGSIb", // 必须是 16 位密码
    "ClockSkew": 1, //缓冲过期时间 默认5分钟 有效时间 = 过期时间 + 缓冲过期时间
    "DeniedAction": "/api/NoPermission", //无权限路由
    "ErrorAction": "/api/ErrorPage", //错误的路由
    "IgnoreUrls": [ "/Auth/GetToken" ] //忽略验证的url
  },
  "AesKey": {
    "Key": "eettWpsixCi1aaacbaEoHtm/nISpONLqAVJYFRbSR8=",
    "IV": "DKWZFQ7sMI1sdasdsVDYmLsw=="
  },
  "SQLiteDbFilePath": "E:\\ChengYunSu\\bin\\Debug\\netcoreapp3.1\\YysxProduct.db"
}

TestToken 提供固定值

  public class TestToken
    {
        public  static string Issurer = "JWTBearer.Auth";  //发行人
        public static string Audience = "api.auth";       //受众人
        public static string Secret = "q2xiARx$4x3TKqBJ";   //密钥
    }

2、Vue axios 访问

Axios 封装,用$http访问
AxiosPlugin.js

// 引入一次就行
import axios from 'axios'

axios.defaults.baseURL = 'http://localhost:55555'
axios.defaults.timeout = 2000

axios.interceptors.request.use(
  (config) => {
    var tiken = localStorage.getItem('JWT_TOKEN')
    if (tiken) {
      config.headers.Authorization = `bearer ${tiken}`
    }
    return config
  },
  (error) => {
    return Promise.reject(error)
  },
)

axios.interceptors.response.use(
  (res) => {
    // 对响应数据做些事
    if (res.status !== 200) {
      // alert(res.statusText)
      return Promise.reject(res)
    }
    return res
  },

  (error) => {
    if (error.response.status === 401) {
      // 401 说明 token 验证失败
      // 可以直接跳转到登录页面,重新登录获取 token
      location.href = '/login'
    }
    // 返回 response 里的错误信息
    return Promise.reject(error.response.data)
  },
)

// 将 Axios 实例添加到Vue的原型对象上
export default {
  install(Vue) {
    Object.defineProperty(Vue.prototype, '$http', { value: axios })
  },
}

main.js


main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
//css 不能直接引用,变相引用,有好办法请指教。
import './assets/bootstrap-css/bootstrap.min.css'
import './assets/bootstrap-vue-css/bootstrap-vue.min.css'
//引用bootstrap-vue
import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
//导入axios 封装文件
import AxiosPlugin from './libs/AxiosPlugin'
// Install AxiosPlugin
Vue.use(AxiosPlugin)
// Install BootstrapVue
Vue.use(BootstrapVue)
// Optionally install the BootstrapVue icon components plugin
Vue.use(IconsPlugin)

Vue.config.productionTip = false

// eslint-disable-next-line no-new
new Vue({
  el: '#app',
  router,
  template: '<App/>',
  components: { App },
})

main.js

获取jwt tioken 并保存,测试授权访问和无授权访问。
App.Vue

<template>
  <div id="app">
      <b-button variant="danger" @click="getVal1()">getVal1</b-button>
    <b-button variant="success" @click="getVal2()">getVal2</b-button>
    <b-button variant="outline-primary" @click="clear()">Clear V1,V2</b-button>
    <br />
    tokon:{{ token }}
    <br />
    Val1: {{ val1 }}
    <br />
    Val2:{{ val2 }}
  </div>
</template>
<script>
export default {
  name: 'App',
  data() {
    return {
      token: 'App.Vue',
      val1: '',
      val2: '',
    }
  },
  mounted() {
    this.$http
      .get('/auth/GetToken', {
        params: {
          username: '12312345678',
          password: '111111',
          sms: '123456',
        },
      })
      .then((res) => {
        this.token = res.data.token
        localStorage.setItem('JWT_TOKEN', this.token)
      })
      .catch(function () {
        // 请求失败处理
        this.token = 'error'
      })
  },
  methods: {
    getVal1: function () {
      this.$http
        .get('/auth/GetValue1', {
          data: {
            id: '*************',
          },
        })
        .then((res) => (this.val1 = res.data))
        .catch(function () {
          // 请求失败处理
          // this.val1 = 'GetValue1 Error Bearer'
        })
    },
    getVal2: function () {
      this.$http
        .get('/auth/GetValue2', {
          params: {
            id: '$$$$$$$$$$',
          },
        })
        .then((res) => {
          this.val2 = res.data
          this.token = localStorage.getItem('JWT_TOKEN')
        })
        .catch(function () {
          // 请求失败处理
          this.val2 = 'GetValue2 Error'
        })
    },
    clear: function () {
      this.val2 = ''
      this.val1 = ''
      this.token = ''
    },
  },
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

3、总结

Vue axios 前端,core webapi做后台 ,JwtBearer认证 ,JwtBearer 中间件配置、axios 封装访问都没有问题,必须添加跨域控制中间件,来解决前端两次请求导致的错误。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Netcore6.0是微软推出的全新版本的开发框架,它提供了强大且灵活的功能,用于构建Web应用程序和APIWeb API是Netcore6.0中的一项重要功能,它允许我们构建基于HTTP协议的API,并通过JSON格式进行数据交换。 JWT(JSON Web Token)是一种用于在网络应用间传递信息的安全方法。在Netcore6.0中,我们可以使用JWT来实现Web API的授权功能。JWT由三部分组成:头部、载荷和签名。头部包含了令牌的类型和算法,载荷包含了我们想要传递的数据,签名通过使用密钥进行加密来验证令牌的合法性。 在Netcore6.0中,我们可以使用Microsoft提供的Microsoft.AspNetCore.Authentication.JwtBearer包来简单地实现JWT的授权功能。首先,我们需要在Startup.cs文件的ConfigureServices方法中配置JWT的身份验证服务,并指定密钥、颁发者、验证等参数。然后,在Configure方法中启用身份验证中间件和JWT授权中间件。 在Vue3中,我们可以使用Axios库来发送HTTP请求并附带JWT令牌进行授权。Vue3是一种流行的JavaScript框架,用于构建现代化的用户界面。通过Axios,我们可以将JWT令牌添加到请求的Authorization头部中,并在后端接收到请求时进行验证。 为了实现Vue3与Netcore6.0的JWT授权,我们首先需要在Vue3项目中安装Axios库,并配置请求拦截器,在每个请求发送前将JWT令牌添加到请求头中。后端接收到带有JWT令牌的请求后,使用相同的密钥和算法进行解密并验证令牌的合法性。 综上所述,Netcore6.0的Web APIVue3的JWT授权组合,可以实现安全可靠的API授权。通过合理的配置和使用,我们可以保护API免受未经授权的访问,并确保只有经过身份验证的用户才能访问敏感数据或执行特定操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yyshenxiang_1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值