c# - 如何使用 JWT 令牌授权用户对 asp net core web api 做出反应。何时使用自动化标头不记名令牌?
问题描述
我正在使用 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;
}
这是我在反应中的登录组件
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 发出发布请求。首先,我请求获取 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;
解决方案
是的,您需要添加授权标头“Bearer”,您还可以自己创建一个自定义标头并将令牌发送到那里。
现在在后端你放了一个中间件,在你到达之前检查令牌。
在身份验证中,我个人使用 axios,您可以在那里配置一个自动插入标题的 api
推荐阅读
- python - 如何在 Python 中打印金字塔?
- sparql - 在数据集中查找 URI
- facebook-pixel - Facebook 像素不会在 PageView 上发送数据
- momentjs - 无法使用 react-moment Gatsby 解析“./locale”
- php - laravel 6 中的自定义邮件验证模板
- javascript - 在 Jquery 中创建父/子结构时寻求帮助
- python - 从 Flask Celery 调用 Google Speech to Text API 导致 celery 崩溃
- db2 - 未建立连接环境时调用语言接口
- typescript - 打字稿:使用扩展数组时初始化空数组
- r - 如何将频率表转换为趋势分析图