【问题标题】:How to use JWT token to authorize user from react to asp net core web api. When to use autorization header bearer token?如何使用 JWT 令牌授权用户对 asp net core web api 做出反应。何时使用自动化标头不记名令牌?
【发布时间】:2021-12-25 23:13:50
【问题描述】:

我正在使用 Asp net core Web Api 构建 React 应用程序。我实现了 JWT 授权,我将 jwt 令牌存储在本地存储中。我是否需要将其与授权标头“Bearer”的每个请求一起发送到我的 webapi?我是否需要每次在后端检查标头中的令牌?我希望我的用户在提出请求时获得授权,但我不知道该怎么做。

这是我的 JwtService

public class JWTAuthService
    {
        private readonly JwtTokenConfig jwtTokenConfig;
        private readonly ILogger<JWTAuthService> logger;

        public JWTAuthService(
            JwtTokenConfig jwtTokenConfig,
            ILogger<JWTAuthService> logger)
        {
            this.jwtTokenConfig = jwtTokenConfig;
            this.logger = logger;
        }

        public string BuildToken(Claim[] claims)
        {
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this.jwtTokenConfig.Secret));

            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            var token = new JwtSecurityToken(
                    issuer: this.jwtTokenConfig.Issuer,
                    audience: this.jwtTokenConfig.Audience,
                    notBefore: DateTime.Now,
                    claims: claims,
                    expires: DateTime.Now.AddMinutes(this.jwtTokenConfig.AccessTokenExpiration),
                    signingCredentials: creds);

            return new JwtSecurityTokenHandler().WriteToken(token);
        }

        public string BuildRefreshToken()
        {
            var randomNumber = new byte[32];
            using var randomNumberGenerator = RandomNumberGenerator.Create();
            randomNumberGenerator.GetBytes(randomNumber);
            return Convert.ToBase64String(randomNumber);
        }

        public ClaimsPrincipal GetPrincipalFromToken(string token)
        {
            JwtSecurityTokenHandler tokenValidator = new();
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this.jwtTokenConfig.Secret));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            var parameters = new TokenValidationParameters
            {
                ValidateAudience = false,
                ValidateIssuer = false,
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = key,
                ValidateLifetime = false,
            };

            try
            {
                var principal = tokenValidator.ValidateToken(token, parameters, out var securityToken);

                if (!(securityToken is JwtSecurityToken jwtSecurityToken) || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
                {
                    this.logger.LogError($"Token validation failed");
                    return null;
                }

                return principal;
            }
            catch (Exception e)
            {
                this.logger.LogError($"Token validation failed: {e.Message}");
                return null;
            }
        }
    }
}

这是我返回用户 ID 的身份验证

 [HttpPost("user")]
        public string UserAuth([FromBody] string accessToken)
        {
            
            ClaimsPrincipal claimsPrincipal = this.jwtAuthService.GetPrincipalFromToken(accessToken);
            string id = claimsPrincipal.Claims.First(c => c.Type == "id").Value;

           var userId = JsonConvert.SerializeObject(id);
            return userId;

        }

这是我在 react 中的登录组件

const Login = () => {
    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');
    const [redirect, setRedirect] = useState(false);

    const submit = async (e) => {
        e.preventDefault();

        const user = {
            username,
            password,
        };
        
        await fetch('https://localhost:44366/api/AppUsers/login', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            credentials: 'include',
            body: JSON.stringify(user),
        }).then(response => response.json()).then(res => {

            if (res.AccessToken) {
                localStorage.setItem("jwt", res.AccessToken);
            }
        })

        setRedirect(true);
    }

    if (redirect) {
        return <Redirect to="/" />
    }

here is return state

我的主页上有帖子,用户可以在其中提交 cmets。我需要 userId 向我的 Api 发出发布请求。首先,我请求获取 userId,然后发布评论。我知道这不是办法,我需要一些帮助来了解如何做到这一点。

const Card = (props) => {
  const [text, setText] = useState("");
  const [showMore, setShowMore] = useState(false);
  const [userId, setUserId] = useState();

  const {
    postId,
    key,
    profilePicture,
    image,
    comments,
    likedByText,
    likedByNumber,
    hours,
    content,
    title,
    accountName,
  } = props;

  const submitComment = (e, postId) => {
    e.preventDefault();

    const jwt = localStorage.getItem("jwt");
    const fetchUrl = `https://localhost:44366/api/AppUsers/user`;

    const fetchData = () => {
      fetch((fetchUrl),
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(jwt),
        })
        .then((res) => res.json())
        .then((result) => setUserId(result))
        .catch((err) => {
          console.log(err);
        });
    };

    fetchData();

    const id = postId;
    const data = {
      Content: text,
      UserId: userId,
      PostId: id ,
    }

    fetch('https://localhost:44366/api/Comments/create', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        
      },
      body: JSON.stringify(data)
    })
      .catch((error) => {
        console.error('Error:', error);
      });

    setText('');
  }
  return (
    <div className="card" key={id}>
      <header>
        <Profile iconSize="big" image={profilePicture} accountName={accountName} />
      </header>
      <p className='text-center'>{title}</p>
      <p className='text-center'>  {content}</p>
      <ImageSlider slides={image} />

      <CardMenu />
      <div className="likedBy">
        <Profile iconSize="small" image={profilePicture} />
        <span>
          Liked by <strong>{likedByText}</strong> and{" "}
          <strong>{comments.Lenght} 50 others</strong>
        </span>
      </div>
      <div className="comments">
        {comments?.slice(0, 5).map((comment) => (

          <Comment
            key={comment.id}
            accountName={comment.User.FirstName ? comment.User.FirstName : null}
            comment={comment.Content}
          />
        )
        )}

        {showMore && comments?.slice(5).map((comment) => (
          <Comment
            key={comment.id}
            accountName={comment.User.FirstName ? comment.User.FirstName : null}
            comment={comment.Content}
          />
        ))}

        <button type="button" className="button" onClick={() => setShowMore(true)}>Show more comments</button>
      </div>
      
      <div className="timePosted">Before {hours} hours.</div>
      <form data={postId} onSubmit={e => submitComment(e, id)}>
        <div className="addComment">
          <textarea type="text" value={text} placeholder="Напишете коментар" className="commentText" onChange={(e) => setText(e.target.value)} />
          <button className="btn btn-primary" type="submit"  >Post</button>
        </div>
      </form>
    </div>
  );
}

export default Card;

【问题讨论】:

    标签: c# reactjs .net asp.net-core react-hooks


    【解决方案1】:

    是的,您需要添加授权标头“Bearer”,您还可以自己创建一个自定义标头并将令牌发送到那里。

    现在您在后端放置一个中间件,在您到达之前检查令牌。

    在身份验证中我个人使用 axios,您可以在那里配置一个自动插入 Header 的 api

    【讨论】:

    • 你能告诉我更多关于那个中间件的信息吗?我是否需要检查令牌是否有效,或者我只需要检查请求中是否有该令牌并接受该用户已授权?
    • 我更像是一个 nodejs 开发人员,但它应该是相似的,你首先检查你是否获得授权,然后检查令牌是否有效,当它有效时你可以转发有效负载,这样你就可以将数据用于不同的诸如用户ID之类的东西
    猜你喜欢
    • 2020-05-14
    • 2019-08-02
    • 2021-01-28
    • 2021-03-08
    • 2020-06-13
    • 2016-03-23
    • 2020-02-27
    • 2019-06-04
    • 1970-01-01
    相关资源
    最近更新 更多