• refresh token axios


    using System;
    using System.Collections.Generic;
    using System.IdentityModel.Tokens.Jwt;
    using System.Linq;
    using System.Security.Claims;
    using System.Security.Cryptography;
    using System.Text;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore;
    using Microsoft.AspNetCore.Authentication.JwtBearer;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Filters;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.IdentityModel.Tokens;
    
    namespace JsonWebTokenTesting
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                CreateWebHostBuilder(args).Build().Run();
            }
    
            public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
                WebHost.CreateDefaultBuilder(args)
                    .UseStartup<Startup>();
        }
    
        public class Startup
        {
            public Startup()
            {
                JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
            }
    
            public void ConfigureServices(IServiceCollection services)
            {
    
                services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                        .AddJwtBearer(options =>
                        {
                            options.TokenValidationParameters = new TokenValidationParameters
                            {
                                ValidateIssuerSigningKey = true,
                                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("O73xQtVrtLnBIEA+Oaq79x1d2BGOFbmHroVuE4ogrOk=")),
                                ValidateIssuer = true,
                                ValidIssuer = "http://localhost:5000",
                                ValidateAudience = true,
                                ValidAudience = "http://localhost:5000",
                                ValidateLifetime = true,
                                ClockSkew = TimeSpan.FromMinutes(0)
                            };
    
                            options.Events = new JwtBearerEvents
                            {
                                OnAuthenticationFailed = context =>
                                {
                                    if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                                    {
                                        context.HttpContext.Response.Headers.Remove("Token-Expired");
                                        context.HttpContext.Response.Headers.Add("Token-Expired", "Relative");
                                    }
                                    return Task.CompletedTask;
                                }
                            };
                        });
    
                services.AddCors(options =>
                        {
                            options.AddPolicy("default", builder =>
                            {
                                builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials().WithExposedHeaders("Token-Expired"); 
                            });
                        });
    
                services.AddMvc(options =>
                        {
                            options.Filters.Add(new ExceptionFilter());
                        });
            }
    
            public void Configure(IApplicationBuilder app)
            {
                app.UseDeveloperExceptionPage();
                app.UseAuthentication();
                app.UseCors("default");
                app.UseMvc();
            }
        }
    
        public class ExceptionFilter : IExceptionFilter
        {
            public void OnException(ExceptionContext context)
            {
                var exception = context.Exception;
    
                var statusCode = StatusCodes.Status500InternalServerError;
    
                if (exception is SecurityTokenException)
                {
                    statusCode = StatusCodes.Status401Unauthorized;
                    context.HttpContext.Response.Headers.Remove("Token-Expired");
                    context.HttpContext.Response.Headers.Add("Token-Expired", "Absolute");
                }
    
                context.Result = new ObjectResult(exception.Message) { StatusCode = statusCode };
            }
        }
    
        public class TokenCreateInput
        {
            public string Account { get; set; }
            public string Password { get; set; }
        }
    
        public class TokenRefreshInput
        {
            public string AccessToken { get; set; }
            public string RefreshToken { get; set; }
        }
    
        [Route("token")]
        public class TokenController : ControllerBase
        {
            private static readonly Dictionary<string, dynamic> _dict = new Dictionary<string, dynamic>();
    
            [HttpPost("create")]
            public IActionResult Create([FromBody]TokenCreateInput input)
            {
                // todo: check the argument
    
                var userId = "10086"; // todo: validate the user
    
                var accessToken = CreateAccessToken(
                    new Claim[]
                    {
                        new Claim(JwtRegisteredClaimNames.Sub, userId)
                    }
                );
    
                var refreshToken = CreateRefreshToken();
    
                _dict[userId] = new { RefreshToken = refreshToken, RefreshTokenExpires = DateTime.UtcNow.AddSeconds(60) };
    
                return Ok(new { accessToken, refreshToken, _dict });
            }
    
            [HttpPost("refresh")]
            public IActionResult Refresh([FromBody]TokenRefreshInput input)
            {
                // todo: check the argument
    
                var principal = ValidateAccessToken(input.AccessToken);
    
                var userId = principal.Claims.First(v => v.Type == JwtRegisteredClaimNames.Sub)?.Value;
    
                _dict.TryGetValue(userId, out var details);
    
                if (details.RefreshToken == input.RefreshToken && details.RefreshTokenExpires >= DateTime.UtcNow)
                {
                    var accessToken = CreateAccessToken(
                        new Claim[]
                        {
                            new Claim(JwtRegisteredClaimNames.Sub, userId)
                        }
                    );
    
                    var refreshToken = CreateRefreshToken();
    
                    _dict[userId] = new { RefreshToken = refreshToken, RefreshTokenExpires = DateTime.UtcNow.AddSeconds(60) };
    
                    return Ok(new { accessToken, refreshToken, _dict });
                }
                else
                {
                    throw new SecurityTokenException("Invalid RefreshToken");
                }
            }
    
            private string CreateAccessToken(Claim[] claims)
            {
                return new JwtSecurityTokenHandler().WriteToken(
                    new JwtSecurityToken(
                        issuer: "http://localhost:5000",
                        audience: "http://localhost:5000",
                        claims: claims,
                        notBefore: DateTime.UtcNow,
                        expires: DateTime.UtcNow.AddSeconds(20),
                        signingCredentials: new SigningCredentials(
                            key: new SymmetricSecurityKey(Encoding.UTF8.GetBytes("O73xQtVrtLnBIEA+Oaq79x1d2BGOFbmHroVuE4ogrOk=")),
                            algorithm: SecurityAlgorithms.HmacSha256
                        )
                    )
                );
            }
    
            private string CreateRefreshToken()
            {
                var random = new byte[32];
                using (var generator = RandomNumberGenerator.Create())
                {
                    generator.GetBytes(random);
                    return Convert.ToBase64String(random);
                }
            }
    
            private ClaimsPrincipal ValidateAccessToken(string accessToken)
            {
                try
                {
                    return new JwtSecurityTokenHandler().ValidateToken(
                       accessToken,
                       new TokenValidationParameters
                       {
                           ValidateAudience = false,
                           ValidateIssuer = false,
                           ValidateIssuerSigningKey = true,
                           IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("O73xQtVrtLnBIEA+Oaq79x1d2BGOFbmHroVuE4ogrOk=")),
                           ValidateLifetime = false
                       },
                       out var validatedToken
                    );
                }
                catch (Exception)
                {
                    throw new SecurityTokenException("Invalid AccessToken");
                }
            }
        }
    
        [Authorize]
        [Route("users")]
        public class UserController : ControllerBase
        {
            [HttpGet]
            public IActionResult Get()
            {
                return Ok(User.FindFirst(v => v.Type == JwtRegisteredClaimNames.Sub)?.Value);
            }
        }
    }
    import axios from 'axios'
    
    axios.defaults.baseURL = 'http://localhost:5000'
    
    const tokenRefreshAsync = () => {
        return new Promise((resolve, reject) => {
            axios.post('token/refresh', {
                AccessToken: localStorage.getItem('accessToken'),
                RefreshToken: localStorage.getItem('refreshToken')
            }).then(response => {
                resolve(response.data)
            }).catch(error => {
                reject(error)
            })
        })
    }
    
    axios.interceptors.request.use(
        config => {
            const accessToken = localStorage.getItem('accessToken')
            if (accessToken) {
                config.headers = { 'Authorization': 'Bearer ' + accessToken }
            }
            return config
        },
        error => {
            return Promise.reject(error)
        }
    )
    
    axios.interceptors.response.use(
        response => {
            return response
        },
        async error => {
            if (error && error.response) {
                switch (error.response.status) {
                    case 401:
                        var tokenExpired = error.response.headers['token-expired']
                        if (tokenExpired === 'Relative') {
                            let { accessToken, refreshToken } = await tokenRefreshAsync()
                            localStorage.setItem('accessToken', accessToken)
                            localStorage.setItem('refreshToken', refreshToken)
                            return axios.request(error.config)
                        } else if (tokenExpired === 'Absolute') {
                            localStorage.removeItem('accessToken')
                            localStorage.removeItem('refreshToken')
                            window.alert('需要重新登录')
                        } else {
                            localStorage.removeItem('accessToken')
                            localStorage.removeItem('refreshToken')
                            window.alert('需要重新登录')
                        }
                        break
                }
            }
            return Promise.reject(error)
        }
    )
    
    const http = {
        get: (url, params, config) => {
            return new Promise((resolve, reject) => {
                axios.get(url, { params: params }, config).then(response => {
                    resolve(response.data)
                }).catch(error => {
                    reject(error)
                })
            })
        },
        post: (url, params, config) => {
            return new Promise((resolve, reject) => {
                axios.post(url, params, config).then(response => {
                    resolve(response.data)
                }).catch(error => {
                    reject(error)
                })
            })
        }
    }
    
    export default http
    <template>
      <div>
        <button @click="tokenCreate">token/create</button>
        <br />
        <button @click="users">users</button>
      </div>
    </template>
    
    <script>
      export default {
        data() {
          return {
            msg: 'Welcome to Your Vue.js App'
          }
        },
        methods: {
          async tokenCreate() {
            let { accessToken, refreshToken } = await this.$http.post('token/create', {
              Account: 'Alice',
              Password: '12345'
            })
            localStorage.setItem('accessToken', accessToken)
            localStorage.setItem('refreshToken', refreshToken)
          },
          async users() {
            console.info(await this.$http.get('users'))
          }
        }
      }
    </script>
  • 相关阅读:
    并发编程
    网络与WEB 编程
    包和模块
    元编程
    类和对象
    【算法题 14 LeetCode 147 链表的插入排序】
    剑指offer面试54题
    剑指offer 面试51题
    剑指offer 面试3题
    剑指offer 面试52题
  • 原文地址:https://www.cnblogs.com/xiaowangzhi/p/11785275.html
Copyright © 2020-2023  润新知