2021年12月17日 星期五

asp.net core mvc api 學習心得 (使用JWT驗證權限)

被呼叫端
startup.cs
public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.IncludeErrorDetails = true; 
options.TokenValidationParameters = new TokenValidationParameters { 
        // 透過這項宣告,就可以從 "sub" 取值並設定給 User.Identity.Name
        NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
        // 透過這項宣告,就可以從 "roles" 取值,並可讓 [Authorize] 判斷角色      
        RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",  
        ValidateIssuer = true, 
ValidIssuer = Configuration.GetValue<string>("JwtSettings:Issuer"),
ValidateAudience = false, 
ValidateLifetime = true, 
        ValidateIssuerSigningKey = true, 
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetValue<string>("JwtSettings:SignKey"))) 
};
});

public void Configure(IApplicationBuilder app)
{
app.UseRouting()
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(...);

[Authorize(Roles="xxx,ooo")] // 指定可以存取的角色
[ApiController]    
[Route("api/[controller]")]
public class xxxAPIController : Controller
{        
        [HttpGet("[action]")]
        public async Task<IActionResult> 查詢(int courseid, bool? 尚未確認, bool? 推薦人聯絡未完成, int? sid) // 接收多個簡單變數(字串有預設長度限制,超過會出現 http 404)
        {

public class 未出貨訂單參數
{
public string lineid { get; set; }
}
[HttpPost("[action]")]
public async Task<IActionResult> 未出貨訂單(未出貨訂單參數 p) // 預先定義class 接收物件參數
{           

        [HttpPost("[action]")]
        public async Task<IActionResult> 查詢推薦人聯絡(Dictionary<string, dynamic> p) // 針對多個簡單變數及陣列直接轉換參數
        {
            var ids = (p["ids"] as Newtonsoft.Json.Linq.JArray).ToObject<List<int>>();
            var id = int.Parse(p["id"] as string);
}


呼叫端 (C#)
using (HttpClient httpClient = new HttpClient())
{
        //產生token
        var claims = new List<Claim>() {
                new Claim (JwtRegisteredClaimNames.NameId, 登入帳號),
            };
        roles.ForEach(a => claims.Add(new Claim(ClaimTypes.Role, a.ToString()))); // 加入角色以供被呼叫端驗證是否有權限
        var tokenG = new JwtSecurityToken(
                issuer: validIssuer,
                audience: validAudience,
                claims: claims,
                expires: DateTime.UtcNow.AddDays(1), // 一天後過期
                signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(issuerSigningKey)),
                    SecurityAlgorithms.HmacSha256)
            );
        var tokenHandler = new JwtSecurityTokenHandler();
        string token = new JwtSecurityTokenHandler().WriteToken(tokenG);

httpClient.DefaultRequestHeaders.Authorization =  new AuthenticationHeaderValue("Bearer", token);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var stringContent = new StringContent(JsonConvert.SerializeObject(new { lineid= "12345" }), System.Text.Encoding.UTF8, "application/json");
using (var response = await httpClient.PostAsync("...", stringContent))
{
string responseBody = await response.Content.ReadAsStringAsync();
var jobj = JsonConvert.DeserializeObject<JObject>(responseBody);
}
}


呼叫端 (axios)
將取得的 jwt token 存放在 cookie,每次呼叫時帶入
axios.interceptors.request.use((config: AxiosRequestConfig) => {
    const token = Cookies.get('...');
    if (config.headers) {
        config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
})
axios.get('...', { params: { id:1 } }) // get帶入簡單變數
axios.post('...', null, { params: { id:1 } }) // post帶入簡單變數 (參數值有字數限制,超過會出現 "Request failed with status code 404")
axios.post('...', {id:1,ids:[1,2,3]}) // post帶入物件


※ 設定發布時同步上傳的資料夾及檔案
<ItemGroup>
  <Content Remove="$(SpaRoot)**" />
  <Content Include="資料夾\*" CopyToOutputDirectory="PreserveNewest" /> // 建置動作設為"內容"
</ItemGroup>

沒有留言:

自訂權限驗證機制

// 使用 filter [Route("api/[controller]")] [ApiController] [Authorize] [TypeFilter(typeof(CustomAsyncAuthorizationFilter))] public c...