【问题标题】:ReactJS + .NET Framework 4.7.2 - How to use AuthorizeAttribute in WebAPIReactJS + .NET Framework 4.7.2 - 如何在 WebAPI 中使用 AuthorizeAttribute
【发布时间】:2020-06-30 09:03:19
【问题描述】:

我使用 JSON Web Token (JWT) 创建了带有登录机制的简单 Web 应用程序。我在 Web API 中生成 TOKEN,然后使用 Redux 存储将其存储,这样我就可以在任何我想要的地方访问它。看起来像这样,我正在使用.subscribe() 来跟踪我的loginStore 中的任何更改:

  const loginStore = createStore(loginUserReducer);
  //After I log in, I put TOKEN to storage and reload my app
  loginStore.subscribe(() => {
    loginStore.getState().then(x => {
      if(x) { 
        localStorage.setItem('TOKEN', x);
      } else {
        localStorage.clear();
      }
      window.location.reload();
    });
  });

我在 .Net Framework 4.7.2 中创建了我的 Web API。接下来,我想在我的HomeController 中使用AuthorizeAttribute 进行授权,以保护我的API 免受任何不必要的调用:

public class HomeController : ApiController
{
    List<string> myList = new List<string>
    {
        "Element1",
        "Element2",
        "Element3"
    };

    [Authorize]//I use this for authorization -> using System.Web.Http;
    [HttpGet]
    [Route("api/mylist")]
    public List<string> MyList()
    {
        return this.myList;
    }
}

最后,我使用fetch()方法,并尝试从APImyList获取数据,并在前面的console.log()中显示。

  fetch('https://localhost:XXXXX/api/mylist', {
    method: 'GET',
    headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json'
    },
  }).then(x => {
    console.log(x.json());//Outcome from API
  }).catch(err => {
      console.log(err);
  });

我得到的是一条错误消息:

"Authorization has been denied for this request."

问题:我如何将我的令牌/用户数据/从 React 传递到 Web API,所以AuthorizeAttribute 将允许它并返回我想要的数据?

我们将不胜感激任何解决方案。

我现在没有使用任何用户角色,但是具有自定义属性和角色验证的解决方案会更好:)

【问题讨论】:

    标签: c# .net reactjs authorization asp.net-web-api2


    【解决方案1】:

    好的!我想通了,它实际上真的很容易!如果有人需要,我会添加一个长答案。

    第 1 步:使用 System.IdentityModel.Tokens.JwtMicrosoft.AspNet.WebApi.CorsMicrosoft.AspNet .Cors TOKEN 生成。

    第 2 步:实现 static class TokenManager,您将在其中生成/验证 TOKEN,并在其中放置您的用户角色。 (Implementation source)

    public static class TokenManager
    {
        private static string Secret = "my_secret_key";
        //Use
        private static JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
    
        public static string GenerateToken(string username)
        {
            byte[] key = Convert.FromBase64String(Secret);
            var descriptor = GenerateTokenDescriptor(username, key);
    
            JwtSecurityToken token = handler.CreateJwtSecurityToken(descriptor);
            return handler.WriteToken(token);
        }
    
        private static SecurityTokenDescriptor GenerateTokenDescriptor(string username, byte[] key)
        {
            SymmetricSecurityKey securityKey = new SymmetricSecurityKey(key);
    
            SecurityTokenDescriptor descriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new[] {
                    new Claim(ClaimTypes.Name, username),
                    new Claim(ClaimTypes.Role, "Role1"),//<-- User role!
                    new Claim(ClaimTypes.Role, "Role2")}),//<-- User role!
                Expires = DateTime.UtcNow.AddMinutes(30),//Token takes only UTC time
                SigningCredentials = new SigningCredentials(securityKey,
                SecurityAlgorithms.HmacSha256Signature)
            };
    
            return descriptor;
        }
    
        public static ClaimsPrincipal GetPrincipal(string token)
        {
            try
            {
                JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
                JwtSecurityToken jwtToken = (JwtSecurityToken)tokenHandler.ReadToken(token);
                if (jwtToken == null)
                    return null;
                byte[] key = Convert.FromBase64String(Secret);
                TokenValidationParameters parameters = new TokenValidationParameters()
                {
                    RequireExpirationTime = true,
                    ValidateIssuer = false,
                    ValidateAudience = false,
                    IssuerSigningKey = new SymmetricSecurityKey(key)
                };
                SecurityToken securityToken;
                ClaimsPrincipal principal = tokenHandler.ValidateToken(token,
                      parameters, out securityToken);
                return principal;
            }
            catch (Exception e)
            {
                return null;
            }
        }
    }
    

    注意:我使用此代码生成了my_secret_key

    HMACSHA256 hmac = new HMACSHA256();
    string key = Convert.ToBase64String(hmac.Key);
    

    第 3 步:创建将用于授权的自定义属性

    public class MyAuthorizeAttribute : AuthorizeAttribute
    {
        private readonly string[] allowedroles;
        public MyAuthorizeAttribute(params string[] roles)
        {
            this.allowedroles = roles;
        }
        protected override bool IsAuthorized(HttpActionContext actionContext)
        {
            //Default outcome 
            bool authorize = false;
            //Get TOKEN
            var authToken = actionContext.Request.Headers.Authorization?.Parameter;
            //Check if TOKEN has parameters
            if (authToken != null)
            {
                //Get roles from TOKEN
                List<string> userRoles = TokenManager.GetPrincipal(authToken).FindAll(ClaimTypes.Role).Select(x => x.Value).ToList();
                //Check if any of User Roles is allowed
                authorize = this.allowedroles.Any(x => userRoles.Any(y => y == x));
            }
            //return outcome
            return authorize;
        }
    }
    

    第 4 步:在 Controller

    中使用您的属性
    public class HomeController : ApiController
    {
        List<string> myList = new List<string>
        {
            "Element1",
            "Element2",
            "Element3"
        };
    
        [MyAuthorizeAttribute("Role2")]//Add roles names in parameter
        [HttpGet]
        [Route("api/mylist")]
        public List<string> MyList()
        {
            return this.myList;
        }
    
        [HttpPost]
        [Route("api/login")]
        public HttpResponseMessage Login()
        {
            var myToken = TokenManager.GenerateToken("username");
            return Request.CreateResponse(HttpStatusCode.OK, myToken);
        }
    }
    

    第 5 步:将 TOKEN 保存到 LOCAL STORAGE

    fetch('https://localhost:XXXXX/api/login', {
            method: 'post',
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json',
                'Access-Control-Allow-Origin': '*'
            },
          }).then(x => {
              x.json().then(y => {
                localStorage.setItem('TOKEN', y);
                });
          }).catch(err => {
              console.log(err);
          });
    

    第 6 步:最后,在您的请求的 标头中传递您的 TOKEN

      fetch('https://localhost:XXXXX/api/mylist', {
        method: 'GET',
        headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + localStorage.getItem('TOKEN'),
            'Access-Control-Allow-Origin': '*'
        },
      }).then(x => {
        console.log(x.json());//Outcome from API
      }).catch(err => {
          console.log(err);
      });
    

    完成,应该可以正常工作了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-19
      • 1970-01-01
      • 2019-09-10
      • 2021-12-25
      • 1970-01-01
      • 2022-12-14
      • 1970-01-01
      相关资源
      最近更新 更多