ASP.NET Core 8.0 OpenAPI Swagger 中的某些端点没有身份验证

问题描述 投票:0回答:1

我正在开发 ASP.NET Core 8.0 Web API。您能告诉我为什么某些端点在 Swagger UI 中没有挂锁图标吗?

例如,我的 ASP.NET 本地主机:localhost ASP.NET swagger

另一方面,editor.swagger.io 上的预览是正确的:editor.swagger.io 预览

当我执行请求时(例如到

/authorize
路径),请求标头没有
Authentication
字段。

我认为与第一个问题相关的第二个问题是,单击挂锁后,我会获得所有身份验证选项。

例如,我单击

GET /student
端点,我将得到:本地主机上的所有选项授权。在 editor.swagger.io 中,我将获得一个正确的选项:editor.swagger.io 的一个选项授权

这是我的 openapi.yaml:

openapi: 3.0.3
info:
  title: API schema for research project
  description: API schema for research project
  version: 1.0.0
servers:
  - url: 'localhost'
tags:
  - name: general
  - name: student
    description: Access to student data.
paths:
  /hello:
    get:
      tags:
        - general
      summary: Returns "Hello World!" phrase
      description: Returns "Hello World!" phrase.
      responses:
        '200':
          description: successful operation
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/HelloWorld'
  /authorize:
    post:
      tags:
        - general
      summary: Get authorization JWT token
      description: Returns JWT token for further authorization.
      responses:
        '200':
          description: successful operation
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/JwtToken'
        '401':
          description: unauthorized
      security:
        - jwt_token_auth: []
  /student:
    get:
      tags:
        - student
      summary: Find first n students
      description: Find and return first n students ordered by its IDs.
      parameters:
        - name: results
          in: query
          description: Number of students to return.
          schema:
            type: integer
            default: 1
            minimum: 1
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Student'
        '400':
          description: Invalid 'results' parameter value
        '401':
          description: unauthorized
      security:
        - student_data_auth: []
    post:
      tags:
        - student
      summary: Add a new students
      description: Add a new students
      requestBody:
        description: Create a new students
        content:
          application/json:
            schema:
              type: array
              items:
                $ref: '#/components/schemas/Student'
        required: true
      responses:
        '201':
          description: Created successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Student'
        '400':
          description: Invalid input
        '401':
          description: unauthorized
        '422':
          description: Validation exception
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ErrorMessage'
      security:
        - student_data_auth: []
  /student/{studentId}:
    put:
      tags:
        - student
      summary: Update student
      description: Update student by given ID.
      parameters:
        - name: studentId
          in: path
          description: ID of the student to update
          required: true
          schema:
            type: integer
      requestBody:
        description: Update existing student
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Student'
        required: true
      responses:
        '200':
          description: Updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Student'
        '400':
          description: Invalid input
        '401':
          description: unauthorized
        '404':
          description: Student not found
        '422':
          description: Validation exception
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ErrorMessage'
      security:
        - student_data_auth: []
    patch:
      tags:
        - student
      summary: Update some fields of student
      description: Update some fields of student by given student ID.
      parameters:
        - name: studentId
          in: path
          description: ID of the student to update
          required: true
          schema:
            type: integer
      requestBody:
        description: Update existing student
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Student'
        required: true
      responses:
        '200':
          description: Updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Student'
        '400':
          description: Invalid input
        '401':
          description: unauthorized
        '404':
          description: Student not found
        '422':
          description: Validation exception
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ErrorMessage'
      security:
        - student_data_auth: []
    delete:
      tags:
        - student
      summary: Delete student by ID
      description: Delete student by given ID.
      parameters:
        - name: studentId
          in: path
          description: ID of the student to delete
          required: true
          schema:
            type: integer
      responses:
        '204':
          description: Deleted successfully
        '401':
          description: unauthorized
        '404':
          description: Student not found
      security:
        - student_data_auth: []
components:
  schemas:
    HelloWorld:
      type: string
      example: "Hello World!"
    JwtToken:
      type: string
      example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
    Student:
      type: object
      properties:
        id:
          type: integer
          readOnly: true
          example: 1
        gender:
          type: string
          maxLength: 10
          example: female
        title:
          type: string
          maxLength: 20
          example: Miss
        first_name:
          type: string
          maxLength: 50
          example: Terri
        last_name:
          type: string
          maxLength: 50
          example: Lucas
        email:
          type: string
          maxLength: 100
          example: [email protected]
        dob:
          type: string
          description: date of birth
          format: date
          example: 1964-11-23
        registered:
          type: string
          description: date of registration
          format: date-time
          example: 2014-07-23T03:21:42.259Z
        phone:
          type: string
          maxLength: 20
          example: 03-2662-3559
        id_name:
          type: string
          maxLength: 20
          description: national identification number type
          example: TFN
        id_value:
          type: string
          maxLength: 50
          description: national identification number value
          example: '230000682'
        nat:
          type: string
          maxLength: 10
          description: nationality short code
          example: AU
        location:
          $ref: '#/components/schemas/Location'
        picture:
          $ref: '#/components/schemas/Picture'
    Location:
      type: object
      properties:
        street_number:
          type: integer
          example: 2595
        street_name:
          type: string
          maxLength: 100
          example: Main Street
        city:
          type: string
          maxLength: 100
          example: Tamworth
        state:
          type: string
          maxLength: 100
          example: Queensland
        country:
          type: string
          maxLength: 100
          example: Australia
        postcode:
          type: string
          maxLength: 20
          example: '6066'
        timezone:
          type: string
          maxLength: 10
          example: +5:30
    Picture:
      type: object
      properties:
        large:
          type: string
          maxLength: 255
          example: https://randomuser.me/api/portraits/men/75.jpg
        medium:
          type: string
          maxLength: 255
          example: https://randomuser.me/api/portraits/med/men/75.jpg
        thumbnail:
          type: string
          maxLength: 255
          example: https://randomuser.me/api/portraits/thumb/men/75.jpg
    ErrorMessage:
      type: object
      properties:
        field:
          type: string
          example: first_name
        message:
          type: string
          example: Input must be string
  securitySchemes:
    jwt_token_auth:
      type: http
      scheme: basic
    student_data_auth:
      type: http
      scheme: bearer
      bearerFormat: JWT

我只是补充一下,我的 ASP.NET Core 代码是由 IntelliJ 中的 OpenAPI 生成器生成的。之后我没有任何授权,添加后

OpenApiSecurityRequirement
我得到了上述情况。

swagger asp.net-core-webapi swagger-ui asp.net-core-8
1个回答
0
投票

在您的 OpenAPI 规范中,您定义了两种安全方案。 JWT 令牌通常作为不记名令牌传递,而不是基本身份验证。如果

jwt_token_auth
应该是基于 JWT 的授权,您应该将其定义为 Bearer 令牌。 每个端点指定一个安全要求。确保
yaml
中的安全要求与 ASP.NET Core 后端中的身份验证逻辑一致。

components:
  securitySchemes:
    jwt_token_auth:
      type: http
      scheme: bearer
      bearerFormat: JWT

以下是示例代码:

AuthController.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace StudentApi.Controllers
{
    [ApiController]
    [Route("Auth")]
    public class AuthController : ControllerBase
    {
        [HttpPost("authorize")]  // Maps to POST /Auth/authorize
        public IActionResult Authorize()
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.UTF8.GetBytes("");  
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new[]
                {
                    new Claim(ClaimTypes.Name, "Test User")
                }),
                Expires = DateTime.UtcNow.AddDays(1),
                Issuer = "",  
                Audience = "",
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
            };
            var token = tokenHandler.CreateToken(tokenDescriptor);
            var tokenString = tokenHandler.WriteToken(token);
            return Ok(tokenString);
        }


    }
}

StudentController.cs:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using StudentApi.Models;

namespace StudentApi.Controllers
{
    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    [ApiController]
    [Route("[controller]")]


    public class StudentController : ControllerBase
    {
        private static readonly List<Student> Students = new List<Student>
        {
            new Student { Id = 1, FirstName = "Terri", LastName = "Lucas", Email = "[email protected]" }
        };

        [HttpGet]
        public ActionResult<IEnumerable<Student>> GetStudents(int results = 1)
        {
            return Ok(Students.Take(results));
        }

        [HttpPost]
        public ActionResult<IEnumerable<Student>> AddStudent([FromBody] List<Student> newStudents)
        {
            Students.AddRange(newStudents);
            return CreatedAtAction(nameof(GetStudents), newStudents);
        }

        [HttpPut("{studentId}")]
        public ActionResult<Student> UpdateStudent(int studentId, [FromBody] Student updatedStudent)
        {
            var student = Students.FirstOrDefault(s => s.Id == studentId);
            if (student == null)
                return NotFound();

            student.FirstName = updatedStudent.FirstName;
            student.LastName = updatedStudent.LastName;
            student.Email = updatedStudent.Email;
            return Ok(student);
        }

        [HttpPatch("{studentId}")]
        public ActionResult<Student> PatchStudent(int studentId, [FromBody] Student updatedFields)
        {
            var student = Students.FirstOrDefault(s => s.Id == studentId);
            if (student == null)
                return NotFound();

            if (updatedFields.FirstName != null)
                student.FirstName = updatedFields.FirstName;

            if (updatedFields.LastName != null)
                student.LastName = updatedFields.LastName;

            if (updatedFields.Email != null)
                student.Email = updatedFields.Email;

            return Ok(student);
        }

        [HttpDelete("{studentId}")]
        public IActionResult DeleteStudent(int studentId)
        {
            var student = Students.FirstOrDefault(s => s.Id == studentId);
            if (student == null)
                return NotFound();

            Students.Remove(student);
            return NoContent();
        }
    }
}

程序.cs:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();


builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = "",
        ValidAudience = "",
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(""))
    };
});

builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "Student API", Version = "v1" });

    c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        Description = "JWT Authorization header using the Bearer scheme. Example: \"Bearer {token}\"",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.ApiKey,
        Scheme = "Bearer"
    });

    c.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference
                {
                    Type = ReferenceType.SecurityScheme,
                    Id = "Bearer"
                }
            },
            Array.Empty<string>()
        }
    });
});


var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthentication();
app.UseAuthorization();


app.MapControllers();

app.Run();

enter image description here

enter image description here

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.