Express.js Ara Katmanı
Solidus kimlik bilgilerini doğrulayan ve API rotalarını koruyan Express ara katmanı (middleware) oluşturun. Bu kılavuz JWT doğrulamasını, DID çözümlemesini ve kimlik bilgisi doğrulamasını kapsar.
Ön koşullar
- Node.js 18+
- Mevcut bir Express uygulaması (veya yeni bir tane oluşturun)
1. Bağımlılıkları Kurun
Solidus bir JWT paketi yayınlamıyor (@solidus-network/jwt npm’e hiç yayınlanmadı — bkz. SDK
genel bakış). Oturum token’ları, aşağıdaki DID imza doğrulamasıyla ilgisiz, sıradan bir
uygulama meselesidir, bu yüzden bu kılavuz standart, yaygın olarak kullanılan bir paket olan
jsonwebtoken’ı kullanır.
npm install @solidus-network/sdk @solidus-network/auth jsonwebtoken express
npm install -D @types/express @types/jsonwebtoken typescript2. SDK Örneğini Oluşturun
// src/solidus.ts
import { createSdk } from '@solidus-network/sdk'
export const sdk = createSdk({
mode: 'testnet',
rpcUrl: 'https://rpc.solidus.network',
signerPrivateKey: process.env.SOLIDUS_PRIVATE_KEY!,
})3. Express İstek Türünü Genişletin
Alt taraftaki işleyicilerin kimlik doğrulaması yapılmış kullanıcı verisine erişebilmesi için Express
Request türüne bir user özelliği ekleyin.
// src/types.ts
import type { Request } from 'express'
export interface SolidusUser {
did: string
credentials: string[]
didDocument: {
id: string
verificationMethod: Array<{
id: string
type: string
publicKeyHex: string
}>
}
}
export interface AuthenticatedRequest extends Request {
user?: SolidusUser
}4. Kimlik Doğrulama Ara Katmanını Oluşturun
Bu ara katman, Authorization başlığından bir Bearer token’ı çıkarır, bunu bir Solidus JWT’si
olarak doğrular, kullanıcının DID belgesini çözümler ve kullanıcı bilgisini isteğe ekler.
// src/middleware/solidus-auth.ts
import type { Response, NextFunction } from 'express'
import jwt from 'jsonwebtoken'
import { sdk } from '../solidus'
import type { AuthenticatedRequest, SolidusUser } from '../types'
const SESSION_JWT_SECRET = process.env.SESSION_JWT_SECRET!
export async function solidusAuth(
req: AuthenticatedRequest,
res: Response,
next: NextFunction
) {
// Extract the Bearer token
const authHeader = req.headers.authorization
if (!authHeader || !authHeader.startsWith('Bearer ')) {
res.status(401).json({
error: 'unauthorized',
message: 'Missing or malformed Authorization header',
})
return
}
const token = authHeader.slice(7) // Remove "Bearer "
try {
// Verify the session JWT this API issued at login (issuance is
// application-specific — sign { sub: did, credentials } with the same
// SESSION_JWT_SECRET using jwt.sign() from the 'jsonwebtoken' package)
const decoded = jwt.verify(token, SESSION_JWT_SECRET) as jwt.JwtPayload
const did = decoded.sub as string
if (!did || !did.startsWith('did:solidus:')) {
res.status(401).json({
error: 'unauthorized',
message: 'Token does not contain a valid Solidus DID',
})
return
}
// Resolve the DID document from the chain
const didDocument = await sdk.did.resolve(did)
if (!didDocument) {
res.status(401).json({
error: 'unauthorized',
message: 'DID not found on chain',
})
return
}
// Attach user info to the request
req.user = {
did,
credentials: (decoded.credentials as string[]) || [],
didDocument,
}
next()
} catch (err) {
res.status(401).json({
error: 'unauthorized',
message: 'Invalid or expired token',
})
}
}5. İsteğe Bağlı: Belirli Kimlik Bilgilerini Zorunlu Kılma
Kimlik doğrulaması yapılmış kullanıcının belirli kimlik bilgisi türlerine sahip olup olmadığını kontrol eden daha yüksek dereceli bir ara katman.
// src/middleware/require-credential.ts
import type { Response, NextFunction } from 'express'
import type { AuthenticatedRequest } from '../types'
export function requireCredential(...requiredTypes: string[]) {
return (
req: AuthenticatedRequest,
res: Response,
next: NextFunction
) => {
if (!req.user) {
res.status(401).json({
error: 'unauthorized',
message: 'Authentication required',
})
return
}
const missing = requiredTypes.filter(
(type) => !req.user!.credentials.includes(type)
)
if (missing.length > 0) {
res.status(403).json({
error: 'forbidden',
message: 'Missing required credentials',
missing,
})
return
}
next()
}
}6. Korunan Rota: Kullanıcı Profili
Kimlik doğrulaması yapılmış kullanıcının kimlik bilgisini döndüren bir uç nokta.
// src/routes/profile.ts
import { Router } from 'express'
import { solidusAuth } from '../middleware/solidus-auth'
import type { AuthenticatedRequest } from '../types'
const router = Router()
router.get(
'/api/profile',
solidusAuth,
(req: AuthenticatedRequest, res) => {
const user = req.user!
res.json({
did: user.did,
credentials: user.credentials,
verificationMethods: user.didDocument.verificationMethod.map(
(vm) => ({
id: vm.id,
type: vm.type,
})
),
})
}
)
export default router7. Kimlik Bilgisi Doğrulama Uç Noktası
Bir kimlik bilgisi kimliğini kabul eden ve zincir üzerinde geçerliliğini kontrol eden bir uç nokta. Bu, hizmetinizin doğrudan sunulan kimlik bilgilerini doğrulaması gerektiğinde kullanışlıdır (JWT oturum akışının dışında).
// src/routes/verify-credential.ts
import { Router } from 'express'
import { sdk } from '../solidus'
const router = Router()
router.post('/api/verify-credential', async (req, res) => {
const { credentialId } = req.body
if (!credentialId) {
res.status(400).json({
error: 'bad_request',
message: 'Request body must include a "credentialId" field',
})
return
}
try {
// Verify signature, expiry, and revocation status by credential ID
const result = await sdk.credentials.verify(credentialId)
res.json({
valid: result.valid,
checks: result.checks, // { signature, expiry, revocation }
credentialId: result.credentialId,
error: result.error,
})
} catch (err) {
res.status(422).json({
error: 'verification_error',
message: err instanceof Error ? err.message : 'Verification failed',
})
}
})
export default router8. Her Şeyi Birbirine Bağlayın
// src/app.ts
import express from 'express'
import profileRoutes from './routes/profile'
import verifyRoutes from './routes/verify-credential'
import { solidusAuth } from './middleware/solidus-auth'
import { requireCredential } from './middleware/require-credential'
import type { AuthenticatedRequest } from './types'
const app = express()
app.use(express.json())
// Public routes
app.get('/api/health', (_req, res) => {
res.json({ status: 'ok' })
})
// Credential verification (public — anyone can verify a credential)
app.use(verifyRoutes)
// Protected routes (require valid JWT)
app.use(profileRoutes)
// Route requiring a specific credential type
app.get(
'/api/premium',
solidusAuth,
requireCredential('KYCCredential'),
(req: AuthenticatedRequest, res) => {
res.json({
message: 'Welcome, verified user',
did: req.user!.did,
})
}
)
const PORT = process.env.PORT || 3001
app.listen(PORT, () => {
console.log(\`Server running on port ${PORT}\`)
})9. cURL ile Test Edin
Sunucuyu başlatın ve uç noktaları test edin.
# Health check
curl http://localhost:3001/api/health
# Get profile (requires valid JWT)
curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
http://localhost:3001/api/profile
# Verify a credential (by ID)
curl -X POST http://localhost:3001/api/verify-credential \
-H "Content-Type: application/json" \
-d '{ "credentialId": "urn:solidus:credential:..." }'Proje Yapısı
express-solidus-api/
src/
solidus.ts # SDK instance
types.ts # Request type extensions
middleware/
solidus-auth.ts # JWT + DID verification
require-credential.ts # Credential type gating
routes/
profile.ts # GET /api/profile
verify-credential.ts # POST /api/verify-credential
app.ts # Express app setup
.env
package.json
tsconfig.jsonSonraki Adımlar
- Next.js Entegrasyonu — App Router ile tam yığın (full-stack) entegrasyon
- Kimlik Bilgisi Akışı — kimlik bilgisi yaşam döngüsünü anlayın
- Webhook’lar — doğrulama olayları için gerçek zamanlı bildirimler alın