Web Components IAM
Web Components Identity Access Management Custom Elements Shadow DOM OAuth RBAC Login Session Token JWT Permission Guard Security Production
| Component | Purpose | Attributes | Events | Security |
|---|---|---|---|---|
| login-form | Authentication UI | auth-url redirect-url | login-success login-error | CSRF Token |
| oauth-button | Social Login | provider client-id | oauth-callback | State param |
| permission-guard | RBAC UI | required-role fallback | access-denied | Server verify |
| session-timer | Session Management | timeout warn-before | session-expired | httpOnly cookie |
| user-profile | User Info Display | show-role show-avatar | profile-updated | Sanitize output |
| mfa-input | 2FA Code Input | digits verify-url | mfa-verified | Rate limiting |
Custom Element Implementation
# === Web Component — Login Form ===
# class LoginForm extends HTMLElement {
# constructor() {
# super();
# this.attachShadow({ mode: 'open' });
# }
#
# static get observedAttributes() {
# return ['auth-url', 'redirect-url'];
# }
#
# connectedCallback() {
# this.shadowRoot.innerHTML = `
# <style>
# :host { display: block; max-width: 400px; margin: 0 auto; }
# form { display: flex; flex-direction: column; gap: 16px; }
# input { padding: 12px; border: 1px solid #ccc; border-radius: 8px; }
# button { padding: 12px; background: #4f46e5; color: white; border: none;
# border-radius: 8px; cursor: pointer; font-size: 16px; }
# button:hover { background: #4338ca; }
# .error { color: #ef4444; display: none; }
# </style>
# <form>
# <input type="text" name="username" placeholder="Username" required />
# <input type="password" name="password" placeholder="Password" required />
# <div class="error"></div>
# <button type="submit">Login</button>
# </form>
# `;
# this.shadowRoot.querySelector('form').addEventListener('submit', (e) => {
# e.preventDefault();
# this.handleLogin(e.target);
# });
# }
#
# async handleLogin(form) {
# const data = new FormData(form);
# try {
# const res = await fetch(this.getAttribute('auth-url'), {
# method: 'POST',
# headers: { 'Content-Type': 'application/json' },
# body: JSON.stringify({
# username: data.get('username'),
# password: data.get('password'),
# }),
# credentials: 'include',
# });
# if (res.ok) {
# const { token } = await res.json();
# this.dispatchEvent(new CustomEvent('login-success', {
# detail: { token }, bubbles: true, composed: true
# }));
# }
# } catch (err) {
# this.dispatchEvent(new CustomEvent('login-error', {
# detail: { error: err.message }, bubbles: true, composed: true
# }));
# }
# }
# }
# customElements.define('login-form', LoginForm);
from dataclasses import dataclass
@dataclass
class WebComponentAPI:
lifecycle: str
when_called: str
use_case: str
apis = [
WebComponentAPI("constructor()", "Element created", "Initialize state, attach Shadow DOM"),
WebComponentAPI("connectedCallback()", "Added to DOM", "Render template, add event listeners"),
WebComponentAPI("disconnectedCallback()", "Removed from DOM", "Cleanup listeners, cancel timers"),
WebComponentAPI("attributeChangedCallback()", "Attribute changes", "React to attribute updates"),
WebComponentAPI("adoptedCallback()", "Moved to new document", "Re-initialize if needed"),
WebComponentAPI("observedAttributes", "Static getter", "List attributes to watch"),
]
print("=== Web Component Lifecycle ===")
for a in apis:
print(f" [{a.lifecycle}] When: {a.when_called}")
print(f" Use: {a.use_case}")
RBAC Permission Guard
# === Permission Guard Component ===
# class PermissionGuard extends HTMLElement {
# constructor() {
# super();
# this.attachShadow({ mode: 'open' });
# }
#
# static get observedAttributes() {
# return ['required-role', 'required-permission'];
# }
#
# connectedCallback() {
# this.checkAccess();
# }
#
# async checkAccess() {
# const requiredRole = this.getAttribute('required-role');
# const userRoles = await this.getUserRoles();
#
# if (userRoles.includes(requiredRole)) {
# this.shadowRoot.innerHTML = '<slot></slot>';
# } else {
# this.shadowRoot.innerHTML = '<slot name="fallback"></slot>';
# this.dispatchEvent(new CustomEvent('access-denied', {
# detail: { requiredRole, userRoles },
# bubbles: true, composed: true
# }));
# }
# }
#
# async getUserRoles() {
# const token = document.cookie.match(/token=([^;]+)/)?.[1];
# if (!token) return [];
# const payload = JSON.parse(atob(token.split('.')[1]));
# return payload.roles || [];
# }
# }
# customElements.define('permission-guard', PermissionGuard);
# Usage:
# <permission-guard required-role="admin">
# <admin-dashboard></admin-dashboard>
# <div slot="fallback">Access Denied</div>
# </permission-guard>
@dataclass
class RBACRule:
role: str
permissions: str
ui_access: str
api_access: str
rules = [
RBACRule("admin", "all", "Full dashboard, user management, settings", "All endpoints"),
RBACRule("editor", "read write publish", "Content editor, media library, preview", "CRUD content, media"),
RBACRule("viewer", "read", "View content, reports, analytics", "GET endpoints only"),
RBACRule("moderator", "read write delete-content", "Content moderation, user reports", "Content CRUD, reports"),
RBACRule("guest", "read-public", "Public pages only", "Public API only"),
]
print("\n=== RBAC Configuration ===")
for r in rules:
print(f" [{r.role}] Permissions: {r.permissions}")
print(f" UI: {r.ui_access}")
print(f" API: {r.api_access}")
Security Best Practices
# === IAM Security Checklist ===
@dataclass
class SecurityCheck:
category: str
check: str
implementation: str
risk_if_missing: str
checks = [
SecurityCheck("Authentication", "Use httpOnly Secure cookies for tokens",
"Set-Cookie: token=xxx; HttpOnly; Secure; SameSite=Strict",
"XSS can steal tokens from localStorage"),
SecurityCheck("CSRF", "Include CSRF token in forms",
"Generate token server-side, validate on POST",
"Cross-site form submission attacks"),
SecurityCheck("XSS", "Shadow DOM encapsulation + sanitize",
"Shadow DOM isolates styles, sanitize user input",
"Script injection, session hijacking"),
SecurityCheck("Session", "Server-side session validation",
"Verify token on every request, not just client-side",
"Client-side checks can be bypassed"),
SecurityCheck("RBAC", "Server-side permission check",
"Never rely on UI hiding alone, verify on API",
"Users can inspect/modify DOM to bypass UI guards"),
SecurityCheck("Rate Limit", "Login attempt limiting",
"Max 5 attempts per minute, lockout after 10",
"Brute force password attacks"),
SecurityCheck("MFA", "Two-factor authentication",
"TOTP (Google Authenticator) or SMS backup",
"Single-factor compromise = full access"),
SecurityCheck("Audit", "Log all auth events",
"Log login, logout, failed attempts, permission changes",
"No visibility into security incidents"),
]
print("Security Checklist:")
for c in checks:
print(f" [{c.category}] {c.check}")
print(f" How: {c.implementation}")
print(f" Risk: {c.risk_if_missing}")
เคล็ดลับ
- Shadow DOM: ใช้ Shadow DOM ป้องกัน Style Leak และ XSS
- Server: ตรวจสอบ Permission ที่ Server เสมอ ไม่พึ่ง UI อย่างเดียว
- httpOnly: เก็บ Token ใน httpOnly Cookie ไม่ใช่ localStorage
- Events: ใช้ Custom Events สื่อสารระหว่าง Components
- Reusable: ออกแบบ Component ให้ Configurable ด้วย Attributes
Web Components สำหรับ IAM คืออะไร
Web Standard Reusable Custom Elements Shadow DOM Login OAuth RBAC Permission Guard Session ใช้ทุก Framework React Vue Angular Vanilla
สร้าง Login Component อย่างไร
Custom Element HTMLElement Shadow DOM Template Form API Request Token httpOnly Cookie Custom Event login-success login-error Attribute Configurable
RBAC UI ทำอย่างไร
Permission Guard Component required-role Attribute JWT Token Role Slot Content Fallback Role Badge Permission Matrix CSS Custom Properties Server Verify
จัดการ Session อย่างไร
Session Manager Token Expiry Countdown Refresh Token Modal เตือน Redirect Login Activity Mouse Keyboard BroadcastChannel Tab Shadow DOM XSS
สรุป
Web Components IAM Custom Elements Shadow DOM OAuth RBAC Login Permission Guard Session Token JWT Security httpOnly CSRF XSS Production
