Skip to main content

Security API

Documentación Swagger

Entonces ¿el endpoint está ahí y cualquiera puede hacer lo que quiera? Claro que no.

Volviendo al top level de la especificación tenemos el security que espera una lista de Security Requirement Object que serán usados por las operaciones dentro de la API. Podemos definir un alcance de cada uno de estos objetos en una lista para aplicación global. Es posible sobrescribir dentro de cada operación caso necesario.

Las definiciones de estos objetos están dentro de components en securitySchemes.

alt text

#...
security:
- MeuApiKeyAuth: [] # Security Requirement Object para `ApiKeyAuth`, lista vacía pues no hay alcances.
- MeuOutroApiKeyAuth: []
components:
##...
securitySchemes: # <<<<<<<<<<<<<<<<<<< aquí dentro
MeuApiKeyAuth:
#...
MeuOutroApiKeyAuth:
#..
## ...

Definir un securitySchema depende del tipo de autenticación que deseas usar. Los posibles parámetros utilizados aquí son:

  • type: REQUIRED y puede ser "apiKey", "http", "mutualTLS", "oauth2", "openIdConnect"
  • description:
  • name Solo usado cuando el type es "apiKey" siendo Obligatorio
  • in: Solo usado cuando el type es "apiKey" y los posibles valores son "query", "header", or "cookie" siendo Obligatorio.
  • scheme Solo usado cuando el type es "http" siendo Obligatorio
  • bearerFormat Solo usado cuando el type es "http" con bearer token
  • flows Solo usado cuando el type es "oauth2" siendo Obligatorio
  • openIdConnectUrl Solo usado cuando el type es "openIdConnect" siendo Obligatorio

Podemos ver que tenemos muchas opciones dependiendo del type elegido.

Vamos a ilustrar rápidamente solo para ver dónde se define cada cosa.

openapi: 3.0.0
info:
#...
security: # Nivel global
- ApiKeyAuth: []

paths:
/example:
get:
summary: Example endpoint
description: Este endpoint requiere una clave de API en el encabezado.
# El campo abajo sobrescribiría la seguridad global, si es necesario.
# Nivel local
# security: ##
# - ApiKeyAuth: []
responses:
#...
#...
components:
securitySchemes:
ApiKeyAuth:
type: apiKey
description: Access using an API Key
name: X-API-KEY
in: header

No vamos a profundizar mucho sobre los tipos de autenticación, sino cómo usarlos.

Entendiendo lo anterior, voy a colocar la API completa del estudio y comentar solamente la parte de seguridad. Esta es la api final que después vamos a usarla para generación de código.

openapi: 3.0.2
info:
title: OpenAPI Course
description: Specification for OpenAPI Course
termsOfService: http://example.com/terms/
contact:
name: David Puziol
url: https://devsecops.puziol.com.br
email: [email protected]
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
version: "1.0"
servers:
- url: https://dev.example.com
description: Development Server
- url: https://qa.example.com
description: QA Server
- url: https://prod.example.com
description: Production Server
externalDocs:
description: Learn more about how to use the API at devsecops.puziol.com.br
url: https://devsecops.puziol.com.br/docs/development/openapi/1.0%20-%20OpenApi

security: # Forzará estas dos autenticaciones en todas las operaciones de todos los endpoints.
- BasicAuth: []
- JwtAuthToken: []

paths:
/v1/customers:
get:
summary: List of Customers
description: Get a list of customers in the system
operationId: listCustomersV1
externalDocs:
description: Learn more about how to use the API at devsecops.puziol.com.br
url: https://devsecops.puziol.com.br/docs/development/openapi/1.0%20-%20OpenApi
tags:
- Customer
security: [] # Sobrescribir aquí para no necesitar autenticación
parameters:
- $ref: "#/components/parameters/PageNumber"
- $ref: "#/components/parameters/PageSize"
requestBody:
description: user to add to the system
required: true
content:
text/plain:
schema:
type: array
items:
type: string
responses:
200:
description: List of Customers
content:
application/json:
schema:
$ref: '#/components/schemas/CustomerPagedList'
post:
summary: New Customer
description: Create a new customer
operationId: newCustomer
tags:
- Customer
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Customer'
responses:
201:
description: New Customer Created
headers:
location:
schema:
description: Location of the created resource
type: string
format: uri
400:
description: Bad Request
409:
description: Conflict

/v1/customers/{Id}:
get:
summary: Get a Customer
description: Get a single customer by its ID value
operationId: getCustomerById
tags:
- Customer
parameters:
- $ref: '#/components/parameters/Id'
responses:
200:
description: Found Customer
content:
application/json:
schema:
$ref: '#/components/schemas/Customer'
404:
description: Not found
put:
summary: Update Customer
description: Update customer by id.
tags:
- Customer
operationId: updateCustomerById
parameters:
- $ref: '#/components/parameters/Id'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Customer'
responses:
204:
description: Customer Updated
400:
description: Bad Request
404:
description: Not found
409:
description: Conflict
delete:
summary: Delete Customer
description: Delete customer by id.
tags:
- Customer
operationId: deleteCustomerById
parameters:
- $ref: '#/components/parameters/Id'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Customer'
responses:
200:
description: Customer Deleted
404:
description: Not found

/v1/customers/{customerId}/orders:
post:
tags:
- Order Service
description: Place Order
parameters:
- name: customerId
in: path
description: Customer Id
required: true
style: simple
explode: false
schema:
type: string
format: uuid
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/BeerOrder'
required: false
responses:
201:
description: Order Created
headers:
Location:
description: Reference to created Order
style: simple
explode: false
schema:
type: string
format: uri
400:
description: Bad Reqeust
404:
description: Not Found
409:
description: Conflict
callbacks:
orderStatusChange:
${request.body#/orderStatusCallbackUrl}:
description: Webhook for order status change notifications
post:
requestBody:
content:
application/json:
schema:
type: object
properties:
orderId:
type: string
format: uuid
orderStatus:
type: string
responses:
200:
description: Okay

/v1/beers:
get:
summary: List of beers
description: Get a list of beers in the system
operationId: listBeers
tags:
- Beer
parameters:
- $ref: "#/components/parameters/PageNumber"
- $ref: "#/components/parameters/PageSize"
responses:
200:
description: List of Beers
content:
application/json:
schema:
$ref: '#/components/schemas/BeerPagedList'
post:
summary: New Beer
description: Create a new beer
operationId: newBeer
tags:
- Beer
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Beer'
responses:
201:
description: New Beer Created
headers:
location:
schema:
description: Location of the created resource
type: string
format: uri
400:
description: Bad Request
409:
description: Conflict

/v1/beer/{Id}:
get:
summary: Get a Customer
description: Get a single customer by its ID value
operationId: getBeerById
tags:
- Beer
parameters:
- $ref: '#/components/parameters/Id' # pero esto traerá el name Id
responses:
200:
description: Found Beer
content:
application/json:
schema:
$ref: '#/components/schemas/Beer'
404:
description: Not found
put:
summary: Update Beer
description: Update beer by id.
tags:
- Beer
operationId: updateBeerById
parameters:
- $ref: '#/components/parameters/Id'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Beer'
responses:
204:
description: Customer Updated
400:
description: Bad Request
404:
description: Not found
409:
description: Conflict
delete:
summary: Delete Beer
description: Delete beer by id.
tags:
- Beer
operationId: deleteBeerById
parameters:
- $ref: '#/components/parameters/Id'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Beer'
responses:
200:
description: Beer Deleted
404:
description: Not found

components:
securitySchemes:
## Nuestros dos tipos de autenticación
BasicAuth:
type: http
scheme: basic
JwtAuthToken:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
Address:
type: object
properties:
line1:
type: string
example: 123 main
city:
type: string
example: St Pete
stateCode:
maxLength: 2
minLength: 2
type: string
description: 2 Letter State Code
enum:
- AL
- AK
- AZ
- AR
- CA
zipCode:
type: string
example: "33701"
Customer:
type: object
properties:
id:
type: string
format: uuid
readOnly: true
firstName:
maxLength: 100
minLength: 2
type: string
example: John
lastName:
maxLength: 100
minLength: 2
type: string
example: Thompson
address:
$ref: '#/components/schemas/Address'
description: customer object
CustomerList:
maxItems: 100
minItems: 1
type: array
description: List of Customers
items:
$ref: '#/components/schemas/Customer'
CustomerPagedList:
type: object
properties:
content:
$ref: '#/components/schemas/CustomerList'
allOf:
- $ref: '#/components/schemas/PagedResponse'
Brewery:
type: object
properties:
name:
type: string
location:
type: string
Beer:
type: object
properties:
id:
type: string
format: uuid
readOnly: true
beerName:
type: string
style:
type: string
enum:
- ALE
- PALE_ALE
- IPA
- WHEAT
- LAGER
price:
type: number
format: float
quantityOnHand:
type: integer
format: int32
brewery:
$ref: '#/components/schemas/Brewery'
description: Beer Object
BeerList:
type: array
items:
$ref: '#/components/schemas/Beer'
BeerPagedList:
type: object
properties:
content:
$ref: '#/components/schemas/BeerList'
allOf:
- $ref: '#/components/schemas/PagedResponse'
BeerOrder:
required:
- customerId
type: object
properties:
id:
type: string
format: uuid
nullable: true
readOnly: true
customerId:
type: string
format: uuid
customerRef:
type: string
nullable: true
beerOrderLines:
type: array
items:
$ref: '#/components/schemas/BeerOrderLine'
orderStatusCallbackUrl:
type: string
format: uri
BeerOrderLine:
required:
- orderQuantity
- upc
type: object
properties:
id:
type: string
format: uuid
nullable: true
readOnly: true
beerId:
type: string
format: uuid
readOnly: true
upc:
type: string
orderQuantity:
maximum: 999
minimum: 1
type: integer
quantityAllocated:
type: integer
nullable: true
readOnly: true
PagedResponse:
type: object
properties:
pageable:
$ref: '#/components/schemas/PagedResponse_pageable'
totalPages:
type: integer
format: int32
last:
type: boolean
totalElements:
type: integer
format: int32
size:
type: integer
format: int32
number:
type: integer
format: int32
numberOfElements:
type: integer
format: int32
sort:
$ref: '#/components/schemas/PagedResponse_pageable_sort'
first:
type: boolean
PagedResponse_pageable_sort:
type: object
properties:
sorted:
type: boolean
unsorted:
type: boolean
PagedResponse_pageable:
type: object
properties:
sort:
$ref: '#/components/schemas/PagedResponse_pageable_sort'
offset:
type: integer
format: int32
pageNumber:
type: integer
format: int32
pageSize:
type: integer
format: int32
paged:
type: boolean
unpaged:
type: boolean
parameters:
PageNumber:
name: pageNumber
in: query
description: Page number
schema:
type: integer
format: int32
default: 1
PageSize:
name: pageSize
in: query
required: false # este ya es el estándar
schema:
type: integer
format: int32
Id:
name: Id
in: path
required: true # este ya es el estándar
description: UUID for Id
schema:
type: string
format: uuid

alt text

Y donde hacer clic que posee el candado aparecerá esto

alt text

Cuando aparezca conectado con cualquier contraseña que coloques en ese momento mostrará así.

alt text

Todas las solicitudes utilizarán ese login a partir de ahora.