本文将为您提供关于RestApiStep6.Prepareforcheckout的详细介绍,同时,我们还将为您提供关于AusefulGitpost-checkouthookforPythonrepos
本文将为您提供关于Rest Api Step 6. Prepare for checkout的详细介绍,同时,我们还将为您提供关于A useful Git post-checkout hook for Python repos、Asp Net Core 5 REST API 使用 RefreshToken 刷新 JWT - Step by Step、Asp.Net Core 5 REST API - Step by Step、asp.net – Paypal Express Checkout集成问题(WEBREQUEST)的实用信息。
本文目录一览:- Rest Api Step 6. Prepare for checkout
- A useful Git post-checkout hook for Python repos
- Asp Net Core 5 REST API 使用 RefreshToken 刷新 JWT - Step by Step
- Asp.Net Core 5 REST API - Step by Step
- asp.net – Paypal Express Checkout集成问题(WEBREQUEST)
Rest Api Step 6. Prepare for checkout
Now that all the items have been added to the cart, we can prepare the order for checkout. This process includes the following steps:
- Estimate shipping costs
- Set shipping and billing information
Estimate shipping costs
Magento calculates shipping costs for each shipping method that can be applied to the order. In this tutorial, the flatrate
($5 per item) and tablerate
shipping methods are active.
Endpoint
POST <host>/rest/<store_code>/V1/carts/mine/estimate-shipping-methods
Headers
Content-Type
application/json
Authorization
Bearer <customer token>
Payload
The payload contains the shipping address.
|
|
Response
Note that the cost for the flatrate
shipping method is $15. The Sprite Yoga Companion Kit bundled product counts as one item. The Advanced Pilates & Yoga item does not have a shipping charge because the customer downloads this item.
|
|
Set shipping and billing information
In this call, you specify the shipping and billing addresses, as well as the selected carrier_code
and method_code
. Since the Table Rate shipping method costs only $5, the customer selected this option.
Magento returns a list of payment options and calculates the order totals.
Endpoint
POST <host>/rest/<store_code>/V1/carts/mine/shipping-information
Headers
Content-Type
application/json
Authorization
Bearer <customer token>
Payload
|
|
Response
The subtotal of the order is $160, and shipping charges are $5. The grand total is $165.
The available payment methods are banktransfer
and checkmo
. The customer will specify a payment method in the next step.
|
|
If you tried this call on your own, and the value of the shipping_amount
parameter is 0
, then you did not deactivate the “Spend $50 or more - shipping is free!” cart price rule. See Deactivate a cart price rule for details.
Verify this step
Sign in as the customer and go to the checkout page.
The payment method is Bank Transfer, the billing and shipping addresses are displayed, and the shipping charges have been calculated.
A useful Git post-checkout hook for Python repos
Every now and again, an innocent python developer checks out a new Git branch then proceeds to bang their head against a bug caused by an orphaned .pyc file from the previous branch. Since *.pyc files are typically in the repo’s .gitignore file, they are not removed when switching branches and can cause issues if the corresponding .py is removed.
This can be neatly addressed through a ‘post checkout’ hook which deletes all such files. Here is such a script, which also removes empty folders and prints a summary:
#!/usr/bin/env bash
# Delete .pyc files and empty directories from root of project
cd ./$(git rev-parse --show-cdup)
# Clean-up
find . -name ".DS_Store" -delete
NUM_PYC_FILES=$( find . -name "*.pyc" | wc -l | tr -d '' '' )
if [ $NUM_PYC_FILES -gt 0 ]; then
find . -name "*.pyc" -delete
printf "\e[00;31mDeleted $NUM_PYC_FILES .pyc files\e[00m\n"
fi
NUM_EMPTY_DIRS=$( find . -type d -empty | wc -l | tr -d '' '' )
if [ $NUM_EMPTY_DIRS -gt 0 ]; then
find . -type d -empty -delete
printf "\e[00;31mDeleted $NUM_EMPTY_DIRS empty directories\e[00m\n"
fi
Sample output:
Finally automated. Stop being bitten by residual .pyc files when switching branches in git. http://stackoverflow.com/questions/1504724/a-git-hook-for-whenever-i-change-branches
Asp Net Core 5 REST API 使用 RefreshToken 刷新 JWT - Step by Step
翻译自 Mohamad Lawand 2021年1月25日的文章 《Refresh JWT with Refresh Tokens in Asp Net Core 5 Rest API Step by Step》 [1]
在本文中,我将向您演示如何在 Asp.Net Core REST API 中将 Refresh Token 添加到 JWT 身份验证。
我们将覆盖的一些主题包含:Refresh Token、一些新的 Endpoints 功能和 JWT(JSON Web Token)。
你也可以在 YouTube 上观看完整的视频[2],还可以下载源代码[3]。
这是 REST API 开发系列的第三部分,前面还有:
- Part 1:Asp.Net Core 5 REST API - Step by Step
- Part 2:Asp.Net Core 5 REST API 使用 JWT 身份验证 - Step by Step
我将基于在上一篇文章中创建的 Todo REST API 应用程序进行当前的讲述。您可以通过阅读上一篇文章并与我一起构建应用程序,或者可以从 github 下载上一篇中的源代码。
在开始实现 Refresh Token 功能之前,让我们先来了解一下 Refresh Token 的运行逻辑是怎样的。
本质上,JWT token 有一个过期时间,时间越短越安全。在 JWT token 过期后,有两种方法可以获取新的 token:
- 要求用户重新登录(这不是一个好的用户体验)。
- 使用 Refresh Token 自动重新验证用户并生成新的 JWT token。
那么,Refresh Token 是什么呢?一个 Refresh Token 可以是任何东西,从字符串到 Guid 到任意组合,只要它是唯一的。
为什么短暂生命周期的 JWT token 很重要,这是因为如果有人窃取了我们的 JWT token 并开始请求我们的服务器,那么该 token 在过期(变得不可用)之前只会持续一小段时间。获取新 token 的唯一方法是使用 Refresh Token 或登录。
另一个重点是,如果用户更改了密码,则根据之前的用户凭据生成的所有 token 会怎样呢。我们并不想使所有会话都失效,我们只需请求刷新 Token,那么将生成一个基于新凭证的新 JWT token。
另外,实现自动刷新 token 的一个好办法是,在客户端发出每个请求之前,都需要检查 token 的过期时间,如果已过期,我们就请求一个新的 token,否则就使用现有的 token 执行请求。
因此,我们将在应用程序中添加一个 Refresh Token,而不仅仅是在每次授权时都只生成一个 JWT token。
那就让我们开始吧,首先我们将更新 Startup
类,通过将 TokenValidationParameters
添加到依赖注入容器,使它在整个应用程序中可用。
var key = Encoding.ASCII.GetBytes(Configuration["JwtConfig:Secret"]);
var tokenValidationParams = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
RequireExpirationTime = false,
ClockSkew = TimeSpan.Zero
};
services.AddSingleton(tokenValidationParams);
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(jwt =>
{
jwt.Savetoken = true;
jwt.TokenValidationParameters = tokenValidationParams;
});
更新完 Startup
类以后,我们需要更新 AuthManagementController
中的 GenerateJwtToken
函数,将 TokenDescriptor
的 Expires
值从之前的值更新为 30 秒(比较合理的值为 5~10 分钟,这里设置为 30 秒只是作演示用),我们需要把它指定的更短一些。
译者注:
实际使用时,可以在 appsettings.json 中为 JwtConfig 添加一个代表 token 过期时间的 ExpiryTimeFrame 配置项,对应的在JwtConfig
类中添加一个ExpiryTimeFrame
属性,然后赋值给TokenDescriptor
的Expires
,这样 token 的过期时间就变得可配置了。
private string GenerateJwtToken(IdentityUser user)
{
var jwtTokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_jwtConfig.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim("Id", user.Id),
new Claim(JwtRegisteredClaimNames.Email, user.Email),
new Claim(JwtRegisteredClaimNames.Sub, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
}),
Expires = DateTime.UtcNow.AddSeconds(30), // 比较合理的值为 5~10 分钟,这里设置 30 秒只是作演示用
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = jwtTokenHandler.Createtoken(tokenDescriptor);
var jwtToken = jwtTokenHandler.Writetoken(token);
return jwtToken;
}
接下来的步骤是更新 Configuration 文件夹中的 AuthResult
,我们需要为 Refresh Token 添加一个新属性:
// Configuration\AuthResult.cs
public class AuthResult
{
public string Token { get; set; }
public string RefreshToken { get; set; }
public bool Success { get; set; }
public List<string> Errors { get; set; }
}
我们将在 Models/DTOs/Requests 中添加一个名为 TokenRequest
的新类,该类负责接收稍后我们将创建的新 Endpoint 的请求参数,用于管理刷新 Token。
// Models\DTOs\Requests\TokenRequest.cs
public class TokenRequest
{
/// <summary>
/// 原 Token
/// </summary>
[required]
public string Token { get; set; }
/// <summary>
/// Refresh Token
/// </summary>
[required]
public string RefreshToken { get; set; }
}
下一步是在我们的 Models 文件夹中创建一个名为 RefreshToken
的新模型。
// Models\RefreshToken.cs
public class RefreshToken
{
public int Id { get; set; }
public string UserId { get; set; } // 连接到 ASP.Net Identity User Id
public string Token { get; set; } // Refresh Token
public string JwtId { get; set; } // 使用 JwtId 映射到对应的 token
public bool IsUsed { get; set; } // 如果已经使用过它,我们不想使用相同的 refresh token 生成新的 JWT token
public bool IsRevorked { get; set; } // 是否出于安全原因已将其撤销
public DateTime AddedDate { get; set; }
public DateTime ExpiryDate { get; set; } // refresh token 的生命周期很长,可以持续数月
[ForeignKey(nameof(UserId))]
public IdentityUser User {get;set;}
}
添加 RefreshToken
模型后,我们需要更新 ApiDbContext
类:
public virtual DbSet<RefreshToken> RefreshTokens { get; set; }
现在让我们为 ApiDbContext
创建数据库迁移,以便可以反映数据库中的更改:
dotnet ef migrations add "Added refresh tokens table"
dotnet ef database update
下一步是在 AuthManagementController
中创建一个新的名为 RefreshToken
的 Endpoind。需要做的第一件事是注入 TokenValidationParameters
:
private readonly UserManager<IdentityUser> _userManager;
private readonly JwtConfig _jwtConfig;
private readonly TokenValidationParameters _tokenValidationParams;
private readonly ApiDbContext _apiDbContext;
public AuthManagementController(
UserManager<IdentityUser> userManager,
IOptionsMonitor<JwtConfig> optionsMonitor,
TokenValidationParameters tokenValidationParams,
ApiDbContext apiDbContext)
{
_userManager = userManager;
_jwtConfig = optionsMonitor.CurrentValue;
_tokenValidationParams = tokenValidationParams;
_apiDbContext = apiDbContext;
}
注入所需的参数后,我们需要更新 GenerateJwtToken
函数以包含 Refresh Token:
private async Task<AuthResult> GenerateJwtToken(IdentityUser user)
{
var jwtTokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_jwtConfig.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim("Id", user.Id),
new Claim(JwtRegisteredClaimNames.Email, user.Email),
new Claim(JwtRegisteredClaimNames.Sub, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
}),
Expires = DateTime.UtcNow.AddSeconds(30), // 比较合理的值为 5~10 分钟,这里设置 30 秒只是作演示用
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = jwtTokenHandler.Createtoken(tokenDescriptor);
var jwtToken = jwtTokenHandler.Writetoken(token);
var refreshToken = new RefreshToken()
{
JwtId = token.Id,
IsUsed = false,
IsRevorked = false,
UserId = user.Id,
AddedDate = DateTime.UtcNow,
ExpiryDate = DateTime.UtcNow.AddMonths(6),
Token = RandomString(25) + Guid.NewGuid()
};
await _apiDbContext.RefreshTokens.AddAsync(refreshToken);
await _apiDbContext.SaveChangesAsync();
return new AuthResult()
{
Token = jwtToken,
Success = true,
RefreshToken = refreshToken.Token
};
}
private string RandomString(int length)
{
var random = new Random();
var chars = "ABCDEFGHIJKLMnopQRSTUVWXYZ0123456789";
return new string(Enumerable.Repeat(chars, length)
.Select(x => x[random.Next(x.Length)]).ToArray());
}
现在,让我们更新两个现有 Action 的返回值,因为我们已经更改了 GenerateJwtToken
的返回类型
Login
Action:
return Ok(await GenerateJwtToken(existingUser));
Register
Action:
return Ok(await GenerateJwtToken(newUser));
然后,我们可以开始构建 RefreshToken
Action:
[HttpPost]
[Route("RefreshToken")]
public async Task<IActionResult> RefreshToken([FromBody] TokenRequest tokenRequest)
{
if (ModelState.IsValid)
{
var result = await VerifyAndGeneratetoken(tokenRequest);
if (result == null)
{
return BadRequest(new RegistrationResponse()
{
Errors = new List<string>()
{
"Invalid tokens"
},
Success = false
});
}
return Ok(result);
}
return BadRequest(new RegistrationResponse()
{
Errors = new List<string>()
{
"Invalid payload"
},
Success = false
});
}
private async Task<AuthResult> VerifyAndGeneratetoken(TokenRequest tokenRequest)
{
var jwtTokenHandler = new JwtSecurityTokenHandler();
try
{
// Validation 1 - Validation JWT token format
// 此验证功能将确保 Token 满足验证参数,并且它是一个真正的 token 而不仅仅是随机字符串
var tokenInVerification = jwtTokenHandler.Validatetoken(tokenRequest.Token, _tokenValidationParams, out var validatedToken);
// Validation 2 - Validate encryption alg
// 检查 token 是否有有效的安全算法
if (validatedToken is JwtSecurityToken jwtSecurityToken)
{
var result = jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase);
if (result == false)
{
return null;
}
}
// Validation 3 - validate expiry date
// 验证原 token 的过期时间,得到 unix 时间戳
var utcExpiryDate = long.Parse(tokenInVerification.Claims.FirstOrDefault(x => x.Type == JwtRegisteredClaimNames.Exp).Value);
var expiryDate = UnixTimeStampToDateTime(utcExpiryDate);
if (expiryDate > DateTime.UtcNow)
{
return new AuthResult()
{
Success = false,
Errors = new List<string>()
{
"Token has not yet expired"
}
};
}
// validation 4 - validate existence of the token
// 验证 refresh token 是否存在,是否是保存在数据库的 refresh token
var storedRefreshToken = await _apiDbContext.RefreshTokens.FirstOrDefaultAsync(x => x.Token == tokenRequest.RefreshToken);
if (storedRefreshToken == null)
{
return new AuthResult()
{
Success = false,
Errors = new List<string>()
{
"Refresh Token does not exist"
}
};
}
// Validation 5 - 检查存储的 RefreshToken 是否已过期
// Check the date of the saved refresh token if it has expired
if (DateTime.UtcNow > storedRefreshToken.ExpiryDate)
{
return new AuthResult()
{
Errors = new List<string>() { "Refresh Token has expired, user needs to re-login" },
Success = false
};
}
// Validation 6 - validate if used
// 验证 refresh token 是否已使用
if (storedRefreshToken.IsUsed)
{
return new AuthResult()
{
Success = false,
Errors = new List<string>()
{
"Refresh Token has been used"
}
};
}
// Validation 7 - validate if revoked
// 检查 refresh token 是否被撤销
if (storedRefreshToken.IsRevorked)
{
return new AuthResult()
{
Success = false,
Errors = new List<string>()
{
"Refresh Token has been revoked"
}
};
}
// Validation 8 - validate the id
// 这里获得原 JWT token Id
var jti = tokenInVerification.Claims.FirstOrDefault(x => x.Type == JwtRegisteredClaimNames.Jti).Value;
// 根据数据库中保存的 Id 验证收到的 token 的 Id
if (storedRefreshToken.JwtId != jti)
{
return new AuthResult()
{
Success = false,
Errors = new List<string>()
{
"The token doesn't mateched the saved token"
}
};
}
// update current token
// 将该 refresh token 设置为已使用
storedRefreshToken.IsUsed = true;
_apiDbContext.RefreshTokens.Update(storedRefreshToken);
await _apiDbContext.SaveChangesAsync();
// 生成一个新的 token
var dbUser = await _userManager.FindByIdAsync(storedRefreshToken.UserId);
return await GenerateJwtToken(dbUser);
}
catch (Exception ex)
{
if (ex.Message.Contains("Lifetime validation Failed. The token is expired."))
{
return new AuthResult()
{
Success = false,
Errors = new List<string>()
{
"Token has expired please re-login"
}
};
}
else
{
return new AuthResult()
{
Success = false,
Errors = new List<string>()
{
"Something went wrong."
}
};
}
}
}
private DateTime UnixTimeStampToDateTime(long unixTimeStamp)
{
var dateTimeVal = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
dateTimeVal = dateTimeVal.AddSeconds(unixTimeStamp).ToLocalTime();
return dateTimeVal;
}
最后,我们需要确保一切可以正常构建和运行。
dotnet build
dotnet run
当我们确定一切 OK 后,我们可以使用 Postman 测试应用程序,测试场景如下所示:
- 登录,生成带有刷新令牌的 JWT 令牌 ⇒ 成功
- 不等待令牌过期而直接尝试刷新令牌 ⇒ 失败
- 等待 JWT 令牌过期然后请求刷新令牌 ⇒ 成功
- 重新使用相同的刷新令牌 ⇒ 失败
感谢您花时间阅读本文。
本文是 API 开发系列的第三部分,你可以通过下面链接阅读前两部分:
- Part 1:Asp.Net Core 5 REST API - Step by Step
- Part 2:Asp.Net Core 5 REST API 使用 JWT 身份验证 - Step by Step
作者 : Mohamad Lawand
译者 : 技术译民
出品 : 技术译站
链接 : 英文原文
https://dev.to/moe23/refresh-jwt-with-refresh-tokens-in-asp-net-core-5-rest-api-step-by-step-3en5 Refresh JWT with Refresh Tokens in Asp Net Core 5 Rest API Step by Step
https://youtu.be/T_Hla1WzaZQ
https://github.com/mohamadlawand087/v8-refreshtokenswithJWT
Asp.Net Core 5 REST API - Step by Step
翻译自 Mohamad Lawand 2021年1月19日的文章 《Asp.Net Core 5 Rest API Step by Step》 [1]
在本文中,我们将创建一个简单的 Asp.Net Core REST API Todo 应用程序,在其中我们可以添加、编辑、删除和查看待办事项,并且将使用 sqlite 来存储数据。
你也可以在 YouTube 上观看完整的视频[2],还可以下载源代码[3]。
这是 API 开发系列的第一部分,后面还有:
- Part 2:Asp.Net Core 5 REST API 使用 JWT 身份验证 - Step by Step [4]
- Part 3:Asp Net Core 5 REST API 中使用 RefreshToken 刷新 JWT - Step by Step
在开始之前,我们需要准备的四样东西:
- Visual Studio code (https://code.visualstudio.com/)
- Dotnet core SDK (https://dotnet.microsoft.com/download)
- Postman (https://www.postman.com/downloads/)
- DBeaver (https://dbeaver.io/download/)
下载并安装了所有必需的工具后,我们需要确保 dotnet SDK 已成功安装,我们需要打开终端并通过检查 dotnet 版本来检查 dotnet SDK 是否已成功安装。
打开终端并输入以下命令:
dotnet --version
现在,我们需要安装 EntityFramework 工具:
dotnet tool install --global dotnet-ef
完成后,我们需要创建我们的应用程序:
dotnet new webapi -n "TodoApp" -lang "C#" -au none
现在让我们添加需要使用的依赖包,以便可以使用 EntityFramrwork 和 sqlite:
dotnet add package Microsoft.EntityFrameworkCore.sqlite
dotnet add package Microsoft.EntityFrameworkCore.Tools
现在,请打开 VS Code 并检查我们的应用程序和源代码,然后,让我们构建应用程序并查看其是否可以运行:
dotnet build
dotnet run
确认可以正常运行后,我们删除由 .Net Core 框架为我们生成的默认模板代码,即删除 WeatherForcastController
和WeatherForcast
类。
接着,我们创建自己的控制器,将其命名为 TodoController
。
然后,我们创建第一个简单的 Action
,将其命名为 TestRun
,让我们开始为我们的控制器编码:
[Route("api/[controller]")] // 我们定义控制器要使用的路由
[ApiController] // 我们需要指定控制器的类型以让 .Net Core 知道
public class TodoController : ControllerBase
{
[Route("TestRun")] // 定义此 Action 的路由
[HttpGet]
public ActionResult TestRun()
{
return Ok("success");
}
}
创建完成后,我们需要对其进行测试,为了测试,我们需要执行以下操作:
dotnet build
dotnet run
应用程序运行起来后,我们可以打开 Postman 试一下看看我们得到的响应。
我们在 Postman 中创建一个新请求,并将类型设置为 GET
,然后请求以下 URL:
https://localhost:5001/api/todo/testrun
正如您在 TestRun 中看到的那样,我们在 Postman 中得到了 “success” 响应。
测试完之后,我们现在需要开始添加模型,在根目录中添加一个 Models 文件夹,并在其中添加一个名为 ItemData
的类。这是一个非常简单的模型,它表示我们的待办事项的列表项。
public class ItemData
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public bool Done { get; set; }
}
添加好模型后,我们需要构建 ApiDbContext
。在根目录中创建一个 Data 文件夹,然后在该文件夹中创建一个名为 ApiDbContext
的新类。
public class ApiDbContext : DbContext
{
public virtual DbSet<ItemData> Items {get;set;}
public ApiDbContext(DbContextOptions<ApiDbContext> options)
: base(options)
{
}
}
然后,我们需要在 appsetting.json
中指定应用程序的连接字符串:
"ConnectionStrings": {
"DefaultConnection" : "DataSource=app.db; Cache=Shared"
}
完善 DbContext 和连接字符串后,我们需要更新 Startup
类,以便可以在应用程序中使用 Application DbContext。在我们的根目录中打开 Startup
类,然后添加以下代码:
services.AddDbContext<ApiDbContext>(options =>
options.Usesqlite(
Configuration.GetConnectionString("DefaultConnection")
));
添加好 DbContext 中间件后,我们需要添加初始化迁移来创建数据库:
dotnet ef migrations add "Initial Migrations"
dotnet ef database update
成功完成数据库更新后,我们可以看到有一个名为 Migrations 的新文件夹,它将包含 C# 脚本,该脚本将负责创建数据库及其表 Items
。我们可以在根目录中看到 app.db 文件,也可以使用 sqlite 查看工具来验证表是否已成功创建,由此我们可以验证数据库是否已创建。
现在,我们已经完成了控制器的所有基础设施的搭建。现在,我们需要开始构建 TodoController
并将其连接到ApiDbContext
。
我们从添加获取待办事项中的所有项的方法 GetItems
开始,依次添加所有需要的方法:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApp.Data;
using TodoApp.Models;
namespace TodoApp.Controllers
{
[Route("api/[controller]")] // api/todo
[ApiController]
public class TodoController : ControllerBase
{
private readonly ApiDbContext _context;
public TodoController(ApiDbContext context)
{
_context = context;
}
[HttpGet]
public async Task<IActionResult> GetItems()
{
var items = await _context.Items.ToListAsync();
return Ok(items);
}
[HttpPost]
public async Task<IActionResult> CreateItem(ItemData data)
{
if (ModelState.IsValid)
{
await _context.Items.AddAsync(data);
await _context.SaveChangesAsync();
return CreatedAtAction("GetItem", new { data.Id }, data);
}
return new JsonResult("Something went wrong") { StatusCode = 500 };
}
[HttpGet("{id}")]
public async Task<IActionResult> GetItem(int id)
{
var item = await _context.Items.FirstOrDefaultAsync(x => x.Id == id);
if (item == null)
return NotFound();
return Ok(item);
}
[HttpPut("{id}")]
public async Task<IActionResult> UpdateItem(int id, ItemData item)
{
if (id != item.Id)
return BadRequest();
var existItem = await _context.Items.FirstOrDefaultAsync(x => x.Id == id);
if (existItem == null)
return NotFound();
existItem.Title = item.Title;
existItem.Description = item.Description;
existItem.Done = item.Done;
// 在数据库级别实施更改
await _context.SaveChangesAsync();
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteItem(int id)
{
var existItem = await _context.Items.FirstOrDefaultAsync(x => x.Id == id);
if (existItem == null)
return NotFound();
_context.Items.Remove(existItem);
await _context.SaveChangesAsync();
return Ok(existItem);
}
}
}
然后,我们可以在 Postman 中一个一个地对它们进行测试。
最后,由于我们在创建 Web API 项目时使用的是 .Net 5,因此 Swagger 已经集成到了我们的应用程序中,要查看 Swagger 界面,可以在浏览器中导航到 http://localhost:5000/swagger/index.html。
Swagger 允许您描述 API 的结构,以便程序可以自动读取它们,而无需我们额外的工作。Swagger 能够读取 API 结构并为我们生成一个 UI,我们可以借此来改善开发体验。
感谢您阅读本文。
本文是 API 开发系列的第一部分,后面会有第二、第三部分。
作者 : Mohamad Lawand
译者 : 技术译民
出品 : 技术译站
链接 : 英文原文
https://dev.to/moe23/asp-net-core-5-rest-api-step-by-step-2mb6 Asp.Net Core 5 Rest API Step by Step
https://youtu.be/p_wUdWshYc8
https://github.com/mohamadlawand087/v6-RestApiNetCore5
https://mp.weixin.qq.com/s/zR0Yz0eUYXzSrctYmE2oWg Asp.Net Core 5 REST API 使用 JWT 身份验证 - Step by Step
asp.net – Paypal Express Checkout集成问题(WEBREQUEST)
所以我把所有的代码都剥离回基本并简单地通过HTTP提交了请求,PLUS方面是我现在从PayPal沙箱服务器得到一个响应,其中ACK = Success和TOKEN = Valid-token-value-这里有一些还返回其他变量,例如CORRELATIONID和TIMESTAMP.
因此,我尝试了一些webrequest示例,我只是得到一个空白屏幕,而不是被重定向到Paypal(沙盒)客户完成付款.
因此,如果任何人都可以发布他们的WebRequest方法,这将是伟大的.
这是我用于webrequest的代码,我确定它错了,但无法确定它出错的地方.
此外,当我在调试期间在localhost上运行代码时,一切正常,并且通过SUCCESS完成调用并收到TOKEN.
当我实时运行时,我在错误异常中收到错误号5,并在状态描述中收到文件“远程主机无法连接”.
这是更新的代码
Function MakeWebRequest(ByVal pUseSandBox As Boolean,ByVal pRequestMethod As String,ByVal pReturnUrl As String,ByVal pCancelUrl As String,ByRef pRtnStatus As String,ByRef pRtnStatusId As HttpStatusCode,ByRef pRtnResponseString As String) As Boolean ' Dim _sxHost As String = nothing Dim _sxEndpoint As String = nothing Dim _sxNameValCol As System.Collections.Specialized.NameValueCollection = nothing Dim _sxResponseCol As System.Collections.Specialized.NameValueCollection = nothing Dim _sxCounta As Integer = nothing Dim _sxParamsstring As String = nothing ' '-> Init _sxParamsstring = "" MakeWebRequest = False _sxNameValCol = New System.Collections.Specialized.NameValueCollection() _sxResponseCol = New System.Collections.Specialized.NameValueCollection() If pUseSandBox Then _sxHost = "http://www.sandBox.paypal.com" _sxEndpoint = "https://api-3t.sandBox.paypal.com/nvp" Else _sxHost = "http://www.paypal.com" _sxEndpoint = "https://api-3t.paypal.com/nvp" End If '-> Create Request Try '-> Key/Value Collection Params _sxNameValCol.Add("METHOD","SetExpressCheckout") _sxNameValCol.Add("USER",_UserName) _sxNameValCol.Add("PWD",_Password) _sxNameValCol.Add("SIGNATURE",_Signature) _sxNameValCol.Add("PAYMENTREQUEST_0_AMT",Format(_Basket.BasketTotalIncDelivery / 100,"0.00")) _sxNameValCol.Add("PAYMENTREQUEST_0_PAYMENTACTION","Sale") _sxNameValCol.Add("PAYMENTREQUEST_0_CURRENCYCODE","GBP") _sxNameValCol.Add("RETURNURL",pReturnUrl) _sxNameValCol.Add("CANCELURL",pCancelUrl) _sxNameValCol.Add("REQCONFIRMSHIPPING","0") _sxNameValCol.Add("NOSHIPPING","2") _sxNameValCol.Add("LOCALECODE","EN") _sxNameValCol.Add("BUTTONSOURCE","PP-ECWizard") _sxNameValCol.Add("VERSION","93.0") '-> UrlEncode For _sxCounta = 0 To _sxNameValCol.Count - 1 If _sxCounta = 0 Then _sxParamsstring = _sxParamsstring & _sxNameValCol.Keys(_sxCounta) & "=" & HttpUtility.UrlEncode(_sxNameValCol(_sxCounta)) Else _sxParamsstring = _sxParamsstring & "&" & _sxNameValCol.Keys(_sxCounta) & "=" & HttpUtility.UrlEncode(_sxNameValCol(_sxCounta)) End If Next '-> Credentials (not used) '_sxRequest.Credentials = CredentialCache.DefaultCredentials Try Dim _sxRequest As WebRequest = DirectCast(System.Net.WebRequest.Create(_sxEndpoint),System.Net.HttpWebRequest) '-> Convert request to byte-array Dim _sxByteArray As Byte() = Encoding.UTF8.GetBytes(_sxParamsstring) _sxRequest.Method = "POST" 'Our method is post,otherwise the buffer (_sxParamsstring) would be useless _sxRequest.ContentType = "application/x-www-form-urlencoded" 'We use form contentType,for the postvars _sxRequest.ContentLength = _sxByteArray.Length 'The length of the buffer (postvars) is used as contentlength Dim _sxPostDataStream As System.IO.Stream = _sxRequest.GetRequestStream() 'We open a stream for writing the postvars _sxPostDataStream.Write(_sxByteArray,_sxByteArray.Length) 'Now we write,and afterwards,we close _sxPostDataStream.Close() 'Closing is always important! '-> Create Response Dim _sxResponse As HttpWebResponse = DirectCast(_sxRequest.GetResponse(),HttpWebResponse) '-> Get Response Status pRtnStatus = _sxResponse.StatusDescription pRtnStatusId = _sxResponse.StatusCode '-> Reponse Stream Dim _sxResponseStream As Stream = _sxResponse.GetResponseStream() 'Open a stream to the response '-> Response Stream Reader Dim _sxStreamReader As New StreamReader(_sxResponseStream) 'Open as reader for the stream pRtnResponseString = _sxStreamReader.ReadToEnd() 'Read the response string MakeWebRequest = True '-> Tidy up _sxStreamReader.Close() _sxResponseStream.Close() _sxResponse.Close() _sxByteArray = nothing _sxPostDataStream = nothing _sxRequest = nothing _sxResponse = nothing _sxResponseStream = nothing _sxStreamReader = nothing Catch ex As Exception pRtnStatusId = Err.Number pRtnStatus = "response(" & ex.Message & ")" Decode(pRtnResponseString,_sxResponseCol) pRtnResponseString = Stringify(_sxResponseCol) End Try Catch ex As Exception pRtnStatusId = Err.Number pRtnStatus = "request(" & ex.Message & ")" Decode(pRtnResponseString,_sxResponseCol) pRtnResponseString = Stringify(_sxResponseCol) End Try '-> Tidy Up _sxHost = nothing _sxEndpoint = nothing _sxNameValCol = nothing _sxResponseCol = nothing _sxCounta = nothing _sxParamsstring = nothing ' End Function
解决方法
TIMESTAMP=2015-07-07T09:07:39Z&CORRELATIONID=7f4d2313c9696&ACK=Failure&VERSION=93.0&BUILD=17276661&L_ERRORCODE0=10002&L_SHORTMESSAGE0=Authentication/Authorization Failed&L_LONGMESSAGE0=You do not have permissions to make this API call&L_SEVERITYCODE0=Error
显然那是因为我测试了一个空白的用户名和密码.
因此,您的服务器设置存在问题,导致您无法在IIS级别或防火墙配置进行外部连接.
如果没有物理存在于您的计算机上,我们可以做很多事情来追踪阻止它的内容,但您可以尝试向其他公共网站(如Google.com)打开HTTP请求,看看这些是否成功.
今天关于Rest Api Step 6. Prepare for checkout的讲解已经结束,谢谢您的阅读,如果想了解更多关于A useful Git post-checkout hook for Python repos、Asp Net Core 5 REST API 使用 RefreshToken 刷新 JWT - Step by Step、Asp.Net Core 5 REST API - Step by Step、asp.net – Paypal Express Checkout集成问题(WEBREQUEST)的相关知识,请在本站搜索。
本文标签: