繁体   English   中英

如何使用 JWT 令牌授权用户响应 asp net core web api。 何时使用授权标头不记名令牌?

[英]How to use JWT token to authorize user from react to asp net core web api. When to use autorization header bearer token?

我使用 Asp net core Web Api 构建 React 应用程序。 我实现了 JWT 授权,将 jwt 令牌存储在本地存储中。 我是否需要将每个请求与授权标头“承载”一起发送到我的 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;

        }

这是我在反应中的登录组件

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

我的主页上有帖子,用户可以在其中提交评论。 我需要 userId 向我的 Api 发出发布请求。 首先,我请求获取用户 ID,然后发布评论。我知道那不是方法,我需要一些有关如何操作的帮助。

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;

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM