Encontrar

文章
· 十二月 23 阅读大约需 5 分钟

在 InterSystems IRIS 中创建和集成 JWT

什么是 JWT?

JWT (JSON Web Token,JSON 网络令牌)是一种开放标准(RFC 7519),它提供了一种轻量级、紧凑、自足的方法,用于在双方之间安全地传输信息。它常用于网络应用程序中的身份验证、授权和信息交换。

JWT 通常由三部分组成:

1.JOSE(JSON Object Signing and Encryption,JSON 对象签名和加密)标头
2.有效载荷
3.签名

这些部分以 Base64Url 格式编码,并用点(.)分隔。

JWT 的结构

标题

{ "alg": "HS256", "typ": "JWT"}

有效载荷

{"sub": "1234567890", "name": "John Doe", "iat": 1516239022}

签名
签名用于验证 JWT 的发件人是否为其本人,并确保信息未被篡改。

创建签名

1. base64 编码报头和有效载荷。
2.使用秘钥(对于对称算法,如 HMAC)或私钥(对于非对称算法,如 RSA)应用签名算法(如 HMAC SHA256 或 RSA)。
3.对结果进行 Base64Url 编码,以获得签名。

JWT 样本。查看JWT 内容

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

在 IRIS 中创建 JWT

注:2024 年以前,%OAuth2.JWT类用于在 IRIS 中生成 JWT。现在,%Net.JSON.JWT类是创建 JWT 的主要类,我将在示例代码中使用该类。

JWK 概述

JWK 表示加密密钥,特别用于签署和验证 JWT。通过 JWK,您可以用一种标准化格式来表示公钥(用于验证)和私钥(用于签名),以便在系统间轻松交换。JWKS 拥有多个 JWK

JWT 工作流程

1.以%DynamicObject 的形式构建头信息,并根据需要添加自定义头信息

2.直接以 %DynamicObject 构建正文/注释

3.调用 %Net.JSON.JWT 类的Create 方法

Set sc = ##Class(%Net.JSON.JWT).Create(header, , claims, jwks, , .JWT)

创建 JWK

Set sc = ##Class(%Net.JSON.JWK).Create("HS256","1212ASD!@#!#@$@#@$$#SDFDGD#%+_)(*@$SFFS",.privateJWK,.publicJWK)

这将返回私钥

{"kty":"oct","k":"MTIxMkFTRCFAIyEjQCRAI0AkJCNTREZER0QjJStfKSgqQCRTRkZT","alg":"HS256"

一些重要的 JWK 属性

"kty":"oct"- 表示 对称 算法
"kty":"RSA" / "kty":"EC"- 表示 非对称 算法

创建 JWK 后,就可以将其添加到JWKS 中。

让我们在 IRIS 中创建 JWKS

Set sc = ##class(%Net.JSON.JWKS).PutJWK(jwk,.JWKS)

此方法返回 JWKS

在 IRIS 中生成 JWT

您可以在 IRIS 中创建对称或非对称密钥 JWT。%Net.JSON.JWK 类主要用于生成 JWT。 在调用该方法之前,请确保在生成JWT 时为对称加密和非对称加密创建并发送了JWKS

对称加密

对称算法使用共享密钥,发送方和接收方都使用相同的密钥来签署和验证 JWT。这些算法,如 HMAC(HS256、HS512、HS384),会为 JWT 有效负载生成散列(签名)。不建议高安全性系统采用这种方法,因为签名和验证都暴露在外,会带来潜在的安全风险。

%Net.JSON.JWK 类中的 Create 方法用于生成 JWK。该方法接收两个输入参数,并返回两个输出参数:

1.算法 - 用于创建 JWK 的算法。
secert - 用于签署和验证 JWT 的密钥。
privateJWK - 创建的私人 JSON 网络密钥。
publicJWK - 创建的公共 JSON Web 密钥。

For symmetric key algorithms - you'll get privateJWK

for Asymmetric key algorithms- You'll get privateJWK and publicJWK
 
对称密钥 JWT

输出

LEARNING>d ##class(Learning.JWT.NetJWT).SymmetricKeyJWT()
privateJWK={"kty":"oct","k":"MTIxMkFTRCFAIyEjQCRAI0AkJCNTREZER0QjJStfKSgqQCRTRkZT","alg":"HS256"}  ; <DYNAMIC OBJECT>
privateJWKS="{""keys"":[{""kty"":""oct"",""k"":""MTIxMkFTRCFAIyEjQCRAI0AkJCNTREZER0QjJStfKSgqQCRTRkZT"",""alg"":""HS256""}]}"
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsIngtYyI6InRlIn0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.PcCs_I8AVy5HsLu-s6kQYWaGvuwqwPAElIad11NpM_E

非对称加密

非对称加密是指使用一对密钥:一个密钥用于签署令牌(私钥),另一个密钥用于验证令牌(公钥)。这与对称加密不同

私钥:该密钥用于签署 JWT。它是保密的,绝对不能暴露。
公钥:此密钥用于验证 JWT 的真实性。它可以安全地共享和分发,因为它不能用来签署新的标记。

您可以通过%SYS.X509Credentials 生成带有私钥/证书的 JWT 非对称加密。

 
非对称 X509

网络应用中的 JWT

2023 版开始,IRIS 默认为网络应用程序内置 JWT 创建功能。在设置网络应用程序时,确保启用 JWT 身份验证

我已添加了有关配置的简要说明

1.在网络应用程序中启用JWT 身份验证
2.如果还没有,创建一个 REST 类
3.包含默认端点资源"/login"。使用基本身份验证调用 REST API,有效载荷为 {"user":"_SYSTEM","password":"SYS"}。
4.4. 响应将是一个 JSON 文件,其中包含 "access_token"、"refresh_token "和其他相关详细信息。
5.5. 使用 "access_token "进行授权。

讨论 (0)1
登录或注册以继续
文章
· 十二月 23 阅读大约需 3 分钟

Minha experiência com APIs e integração de POS

Olá amigo! 😊 Como você está hoje?

Gostaria de compartilhar uma pequena parte dos meus aprendizados no meu primeiro projeto oficial: a integração de máquinas de POS/EDC com nosso sistema de faturamento. Foi um desafio empolgante onde tive experiência prática trabalhando com APIs e fornecedores.

Como uma máquina de pagamento realmente funciona?

É simples: comece iniciando/criando uma transação e, depois, recupere o status do pagamento dela.

Aqui, iniciar/criar refere-se ao método POST, e recuperar refere-se ao GET.

Fluxo de trabalho...

Vamos assumir que o fornecedor nos forneceu um documento com ambas as APIs (Criar e Buscar Status do Pagamento). Exemplos listados abaixo:

 

CRIAR TRANSAÇÃO:

url/endpoint: https://payvendor.com/create-transaction
method: POST
payload: 
{
    "reference_id": "2345678",
    "pos_id": "PISC98765",
    "date_time": "MMDDYYYYHHMMSS"
    "amount": 100
}
response: [200]
{
    "reference_id": "2345678",
    "pos_id": "PISC98765",
    "date_time": "MMDDYYYYHHMMSS"
    "unn": "456789876546787656"
}

BUSCAR STATUS DO PAGAMENTO:

url/endpoint: https://payvendor.com/get-status
method: GET
payload: ?reference_id="2345678"
response: [200]
{
    "reference_id": "2345678",
    "pos_id": "PISC98765",
    "date_time": "MMDDYYYYHHMMSS"
    "unn": "456789876546787656"
    "status": "paid"
    "amount": 100
}

 

Como usamos essas APIs? Vamos descobrir... 🫡

Para consumir essas APIs no ObjectScript, temos um módulo ou classe para realizar requisições HTTP internamente: %Net.HttpRequest.

O básico:

  • Criar uma instância de %Net.HttpRequest.
  • Definir a URL e o método HTTP.
  • Adicionar o cabeçalho (header) e o corpo (body). [se necessário]
  • Enviar a requisição para o servidor.
  • Tratar a resposta.
; --------- EXEMPLO DE REQUISIÇÃO POST ---------
Set req = ##class(%Net.HttpRequest).%New()  ; cria uma instância desta classe
Set req.Server = "https://payvendor.com"    ; o servidor
Set req.Location = "/create-transaction"    ; o endpoint
Set req.Https = 1                           ; 0 para http / 1 para https
Set req.ContentType = "application/json"    ; Tipo de conteúdo
; ---- create the JSON body ----
Set obj = ##class(%DynamicObject).%New()
Set obj."reference_id" = "2345678"      ; ID único
Set obj."pos_id" = "PISC98765"          ; número do dispositivo
Set obj."date_time" = $ZSTRIP($ZDATETIME($HOROLOG,8), "*P") 
Set obj."amount" = 100
; -------------------------------
; ---- enviar requisição ----
Do req.EntityBody.Write(obj.%ToJSON())
Do req.Post()           ; .Post() irá disparar a chamada
; ----------------------
; ---- Resposta ----
Write req.HttpResponse.StatusCode,!     ; CÓDIGO DE STATUS HTTP
Write req.HttpResponse.Data.Read(),!    ; MENSAGEM DE STATUS HTTP
; ------------------

Após criar a transação, podemos manter uma tabela (preferível) ou um global para manter os logs de cada transação.

; --------- EXEMPLO DE REQUISIÇÃO GET ---------
Set req = ##class(%Net.HttpRequest).%New()  ; cria uma instância desta classe
Set req.Server = "https://payvendor.com"    ; o servidor
Set req.Location = "/get-status"            ; o endpoint
Set req.Https = 1                           ; 0 para http / 1 para https
; ---- Parâmetros de Consulta (Query) ----
Do req.SetParam("reference_id", "2345678")

; ---- enviar requisição ----
Do req.Get()           ; .Get() irá disparar a chamada
; ---- Resposta ----
Set stsCode = req.HttpResponse.StatusCode,!     ; CÓDIGO DE STATUS HTTP
If stsCode=200 {
    Set objResponse = req.HttpResponse.Data.Read()
    Set objData = ##class(%DynamicObject).%FromJSON(objResponse)
    Set payStatus = objData.status              ; status do pagamento
}
; ------------------

É assim que buscamos o status do pagamento. Depois de obter o status, podemos atualizá-lo no sistema de faturamento e também em nossos logs.

 

Este fluxo de trabalho é simples, mas à medida que programamos mais, podemos desenvolver frameworks e abordagens melhores. Ao longo da minha experiência, integrei com sucesso 5 fornecedores de POS e 3 gateways de pagamento com nosso sistema de faturamento. Se você tiver alguma dúvida ou precisar de orientação, sinta-se à vontade para entrar em contato!

Também estou aberto a feedbacks. :)

Obrigado...

讨论 (0)1
登录或注册以继续
文章
· 十二月 23 阅读大约需 3 分钟

Destaque do OAuth do FHIR (2024.3+) – Guia rápido para novos clientes

Também nas versões anteriores era possível configurar o seu servidor FHIR para aceitar requisições via OAuth 2.0 (por exemplo, para um cliente SMART on FHIR), mas atualmente, com a versãov2024.3, lançada a algum tempo— existe um novo recurso que torna isso mais fácil: o OAuth FHIR Client QuickStart. 

Esse “QuickStart” é um assistente em formato de wizard que permite conectar seu servidor FHIR a um servidor OAuth e habilitar autenticação e autorização OAuth para requisições FHIR em 5 passos simples (na prática, apenas 3…).

  • Passo 1 - Criar ou novo ou escolher o Servidor FHIR

Você pode já ter um servidor FHIR (endpoint) definido, ou ainda não ter definido um e querer configurá-lo agora, como parte deste QuickStart.

  • Passo 2 - Selecione o Servidor FHIR

Se você optar por “Usar um existente”, serão exibidos os endpoints disponíveis, por namespace. Por exemplo:

Se você optar por “Criar novo”, será exibido um pequeno formulário para criar um novo endpoint.

Isso é semelhante ao que você veria caso criasse o endpoint manualmente anteriormente:

  • Passo 3 - Selecione o tipo de servidor OAuth

Você pode optar por usar um servidor OAuth externo (por exemplo, Auth0 da Okta) ou utilizar o servidor OAuth integrado ao InterSystems IRIS.

Se quiser usar o IRIS como seu servidor OAuth, será necessário configurá-lo como um servidor OAuth com suporte a FHIR. Para isso, também existe um “atalho”: um método que você pode chamar e que realiza essa configuração automaticamente.

Observação: Comunicação Segura (Secure Communication) precisa estar configurada para que isso funcione.

 

  • Passo 4 - Configure o servidor OAuth

Se você optar por usar um servidor OAuth externo, será solicitado o endpoint do emissor (Issuer Endpoint):

Se você já tiver definido um, pode escolhê-lo no menu suspenso; caso contrário, pode digitá-lo (ou colá-lo).

De qualquer forma, é possível testar esse endpoint do servidor OAuth, por exemplo:

  • Passo 5 (ou 4 se você escolheu o servidor OAuth interno do IRIS) – Confirmar

Você verá uma pequena confirmação com informações e um botão “Confirmar”.

Por exemplo (ao optar por criar um novo servidor FHIR e usar o servidor OAuth interno do IRIS):

Ou, por exemplo (ao escolher um endpoint FHIR existente e um servidor OAuth externo):

Se tudo correr bem, você verá uma mensagem indicando que a criação foi bem-sucedida.

Caso contrário, receberá uma mensagem apropriada.

Nos bastidores, você poderá observar algumas coisas -

  • Você verá o cliente definido na lista de clientes OAuth (com seus detalhes):

  • Você verá o cliente definido no seu endpoint FHIR:

  • Na seção geral de Segurança do Management Portal, em OAuth 2.0, você também poderá encontrar uma Definição de Cliente com a Configuração do Cliente.

Assumindo que tudo o que foi descrito acima esteja funcionando, você já pode começar a usar OAuth (e, especificamente, SMART on FHIR) para se comunicar com seu servidor FHIR.

Mais detalhes sobre isso... em um artigo futuro...

讨论 (0)1
登录或注册以继续
文章
· 十二月 23 阅读大约需 4 分钟

Pergunte às suas classes IRIS usando Ollama, IRIS VectorDB e LangChain.

Se você quiser saber se já existe uma classe sobre um determinado tópico fazendo uma simples pergunta em linguagem natural, isso agora é possível. Baixe e execute a aplicação https://openexchange.intersystems.com/package/langchain-iris-tool para conhecer tudo sobre as classes do seu projeto em um chat.

Instalação:

$ git clone https://github.com/yurimarx/langchain-iris-tool.git
$ docker-compose build
$ docker-compose up -d

Como usar:

1. Abra a URL http://localhost:8501

2. Verifique o botão de Configurações usado pelo agente para se conectar ao InterSystems IRIS.

3. Pergunte sobre as classes que você desenvolveu (por exemplo: Existem classes que herdam de Persistent?)

UI 4

Soluções utilizadas:

  1. Ollama – LLM privado e ferramenta de chat com NLP
  2. LangChain – plataforma para construir agentes de IA
  3. Streamlit – framework de frontend
  4. InterSystems IRIS – servidor para responder às perguntas

Sobre Ollama

É uma solução de LLM gratuita e on-premises que permite executar IA Generativa com privacidade e segurança, pois seus dados são processados apenas localmente. O projeto Ollama oferece suporte a diversos modelos, incluindo Mistral, modelos da OpenAI, modelos DeepSeek, entre outros, todos rodando on-premises. Este pacote utiliza o Ollama via Docker Compose com o modelo Mistral:

ollama:
    image: ollama/ollama:latest
    deploy:
      resources:
        reservations:
          devices:
          - driver: nvidia
            capabilities: ["gpu"]
            count: all  # Adjust count for the number of GPUs you want to use
    ports:
      - 11434:11434
    volumes:
      - ./model_files:/model_files
      - .:/code
      - ./ollama:/root/.ollama
    container_name: ollama_iris
    pull_policy: always
    tty: true
    entrypoint: ["/bin/sh", "/model_files/run_ollama.sh"] # Loading the finetuned Mistral with the GGUF file
    restart: always
    environment:
      - OLLAMA_KEEP_ALIVE=24h
      - OLLAMA_HOST=0.0.0.0

Sobre Langchain:

LangChain é um framework para construir aplicações de IA Generativa de forma simples. O LangChain possui o conceito de tool (ferramenta). As ferramentas são plug-ins (aplicações de RAG) usadas pelo LangChain para complementar o trabalho dos LLMs. Esta aplicação implementa uma ferramenta do LangChain para fazer perguntas de gerenciamento e desenvolvimento para o seu servidor IRIS:

from langchain.llms import Ollama
from langchain.chains import RetrievalQA
from langchain.document_loaders import CSVLoader
from langchain.embeddings import OllamaEmbeddings
from langchain_iris import IRISVector

def get_insights(question, csv_file, iris_conn, collection_name):
    
    # Load and process the CSV data    
    loader = CSVLoader(csv_file)
    documents = loader.load()

    llm = Ollama(
        base_url="http://ollama:11434", 
        model="mistral", 
        temperature=0,
    )

    # Create embeddings
    embeddings = OllamaEmbeddings(model="mistral", base_url="http://ollama:11434", temperature=0)

    db = IRISVector.from_documents(
        embedding=embeddings, 
        documents=documents,
        connection_string=iris_conn,
        collection_name=collection_name,
        pre_delete_collection=True
    )

    qa = RetrievalQA.from_chain_type(
        llm=llm,
        chain_type="stuff",
        retriever=db.as_retriever())
    
    return qa({"query": question})

Sobre Streamlit:

O Streamlit é usada para desenvolver frontends utilizando a linguagem Python. Esta aplicação possui um chat em Streamlit para interagir com o Ollama, o LangChain e o IRIS, obtendo respostas relevantes:

import pandas as pd
import streamlit as st
from sqlalchemy import create_engine
import langchain_helper as lch

username = "_system"
password = "SYS"
hostname = "iris"
port = 51972
webport = 52773
namespace = "USER"
st.set_page_config(page_title="InterSystems IRIS Classes Demo", page_icon="📜")

st.title("Langchain IRIS Classes Chat")

with st.popover("Settings"):
    with st.spinner(text="Connecting to the IRIS classes"):
        engine = create_engine("iris://" + username + ":" + password + "@" + hostname + ":" + str(port) + "/" + namespace)
        connection  = engine.connect()
        query = 'select * from %Dictionary.ClassDefinition where substring(ID,1,1) <> \'%\' and  Copyright is null'
        df = pd.read_sql(query, con=connection)
        df.to_csv("classes.csv")
    
    username = st.text_input("Username:", username)
    password = st.text_input("Password:", password)
    hostname = st.text_input("Hostname:", hostname)
    port = int(st.text_input("Port:", port))
    webport = int(st.text_input("Web port:", webport))
    namespace = st.text_input("Namespace:", namespace)

            

# User query input
query = st.text_input(label="Enter your query")

# Submit button
if st.button(label="Ask IRIS Classes", type="primary"):
    
    with st.spinner(text="Generating response"):
        iris_conn_str = f"iris://{username}:{password}@{hostname}:{port}/{namespace}"
        response = lch.get_insights(query, "classes.csv", iris_conn=iris_conn_str, collection_name="classes")
        st.write(response['result'])
讨论 (0)1
登录或注册以继续
摘要
· 十二月 23

Happy Holidays from the Developer Community!

Dear Community Member,

As we close out a remarkable year for the InterSystems Developer Community, we'd like to thank you for being an essential part of our 2025 journey. This year we celebrated an incredible milestone, our 10-Year Anniversary, and your participation, insights, and contributions helped make it truly special.

From new challenges and meetups to innovative applications, articles, and ideas, your engagement has strengthened the community and inspired fellow developers worldwide. We deeply appreciate your dedication and the spirit of collaboration you bring.

Wishing you a joyful and restorative holiday season, and an exciting year ahead filled with learning, creativity, and new accomplishments. We look forward to achieving even more together in 2026.

With appreciation,
The Developer CommunityTeam