guidewire-enterprise-rbac
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGuidewire Enterprise RBAC
Guidewire 企业级RBAC
Overview
概述
Implement comprehensive role-based access control for Guidewire InsuranceSuite including API roles, user permissions, system roles, and security policies.
为Guidewire InsuranceSuite实现全面的基于角色的访问控制(RBAC),涵盖API角色、用户权限、系统角色及安全策略。
Prerequisites
前提条件
- Access to Guidewire Cloud Console (GCC)
- Understanding of OAuth2 and JWT
- Knowledge of enterprise security patterns
- 拥有Guidewire Cloud Console(GCC)的访问权限
- 了解OAuth2和JWT相关知识
- 熟悉企业安全模式
RBAC Architecture
RBAC架构
┌─────────────────────────────────────────────────────────────────────────────────┐
│ Guidewire RBAC Architecture │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ Guidewire Hub (IdP) │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Users │ │ Groups │ │ Applications│ │ Roles │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │ • Internal │ │ • AD Sync │ │ • Browser │ │ • API Roles │ │ │
│ │ │ • External │ │ • Manual │ │ • Service │ │ • App Roles │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────┼───────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐ │
│ │ PolicyCenter │ │ ClaimCenter │ │ BillingCenter │ │
│ │ │ │ │ │ │ │
│ │ System Roles: │ │ System Roles: │ │ System Roles: │ │
│ │ • Underwriter │ │ • Claims Adjuster │ │ • Billing Admin │ │
│ │ • Policy Admin │ │ • Claims Supervisor │ │ • Payment Handler │ │
│ │ • Agent │ │ • SIU Investigator │ │ • Collections Agent │ │
│ │ │ │ │ │ │ │
│ │ API Roles: │ │ API Roles: │ │ API Roles: │ │
│ │ • pc_policy_read │ │ • cc_claim_read │ │ • bc_billing_read │ │
│ │ • pc_policy_admin │ │ • cc_claim_admin │ │ • bc_payment_admin │ │
│ └───────────────────────┘ └───────────────────────┘ └───────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────────────────────────┐
│ Guidewire RBAC Architecture │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ Guidewire Hub (IdP) │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Users │ │ Groups │ │ Applications│ │ Roles │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │ • Internal │ │ • AD Sync │ │ • Browser │ │ • API Roles │ │ │
│ │ │ • External │ │ • Manual │ │ • Service │ │ • App Roles │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────┼───────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐ │
│ │ PolicyCenter │ │ ClaimCenter │ │ BillingCenter │ │
│ │ │ │ │ │ │ │
│ │ System Roles: │ │ System Roles: │ │ System Roles: │ │
│ │ • Underwriter │ │ • Claims Adjuster │ │ • Billing Admin │ │
│ │ • Policy Admin │ │ • Claims Supervisor │ │ • Payment Handler │ │
│ │ • Agent │ │ • SIU Investigator │ │ • Collections Agent │ │
│ │ │ │ │ │ │ │
│ │ API Roles: │ │ API Roles: │ │ API Roles: │ │
│ │ • pc_policy_read │ │ • cc_claim_read │ │ • bc_billing_read │ │
│ │ • pc_policy_admin │ │ • cc_claim_admin │ │ • bc_payment_admin │ │
│ └───────────────────────┘ └───────────────────────┘ └───────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘Instructions
操作步骤
Step 1: Configure API Roles in GCC
步骤1:在GCC中配置API角色
yaml
undefinedyaml
undefinedAPI Role Configuration
API Role Configuration
Guidewire Cloud Console > Identity & Access > API Roles
Guidewire Cloud Console > Identity & Access > API Roles
api_roles:
Read-only roles
- name: pc_policy_read
application: PolicyCenter
description: Read-only access to policies and accounts
permissions:
- endpoint: /account/v1/accounts operations: [GET]
- endpoint: /account/v1/accounts/{id} operations: [GET]
- endpoint: /policy/v1/policies operations: [GET]
- endpoint: /policy/v1/policies/{id} operations: [GET]
Admin roles
- name: pc_policy_admin
application: PolicyCenter
description: Full access to policy administration
permissions:
- endpoint: /account/v1/accounts operations: [GET, POST, PATCH]
- endpoint: /job/v1/submissions operations: [GET, POST, PATCH]
- endpoint: /job/v1/submissions/{id}/quote operations: [POST]
- endpoint: /job/v1/submissions/{id}/bind operations: [POST]
- endpoint: /policy/v1/policies operations: [GET, POST, PATCH]
Claims roles
- name: cc_claim_admin
application: ClaimCenter
description: Full access to claims management
permissions:
- endpoint: /claim/v1/claims operations: [GET, POST, PATCH]
- endpoint: /fnol/v1/fnol operations: [POST]
- endpoint: /claim/v1/claims/{id}/exposures operations: [GET, POST, PATCH]
- endpoint: /claim/v1/claims/{id}/payments operations: [GET, POST]
undefinedapi_roles:
Read-only roles
- name: pc_policy_read
application: PolicyCenter
description: Read-only access to policies and accounts
permissions:
- endpoint: /account/v1/accounts operations: [GET]
- endpoint: /account/v1/accounts/{id} operations: [GET]
- endpoint: /policy/v1/policies operations: [GET]
- endpoint: /policy/v1/policies/{id} operations: [GET]
Admin roles
- name: pc_policy_admin
application: PolicyCenter
description: Full access to policy administration
permissions:
- endpoint: /account/v1/accounts operations: [GET, POST, PATCH]
- endpoint: /job/v1/submissions operations: [GET, POST, PATCH]
- endpoint: /job/v1/submissions/{id}/quote operations: [POST]
- endpoint: /job/v1/submissions/{id}/bind operations: [POST]
- endpoint: /policy/v1/policies operations: [GET, POST, PATCH]
Claims roles
- name: cc_claim_admin
application: ClaimCenter
description: Full access to claims management
permissions:
- endpoint: /claim/v1/claims operations: [GET, POST, PATCH]
- endpoint: /fnol/v1/fnol operations: [POST]
- endpoint: /claim/v1/claims/{id}/exposures operations: [GET, POST, PATCH]
- endpoint: /claim/v1/claims/{id}/payments operations: [GET, POST]
undefinedStep 2: Service Account Configuration
步骤2:服务账号配置
typescript
// Service account management
interface ServiceAccount {
clientId: string;
name: string;
description: string;
apiRoles: string[];
environments: string[];
}
const serviceAccounts: ServiceAccount[] = [
{
clientId: 'integration-service-prod',
name: 'Integration Service',
description: 'Backend integration service for policy and claims sync',
apiRoles: ['pc_policy_admin', 'cc_claim_read'],
environments: ['production']
},
{
clientId: 'agent-portal-prod',
name: 'Agent Portal',
description: 'Agent-facing portal application',
apiRoles: ['pc_policy_read', 'pc_submission_handler'],
environments: ['production', 'uat']
},
{
clientId: 'reporting-service',
name: 'Reporting Service',
description: 'Read-only access for reporting',
apiRoles: ['pc_policy_read', 'cc_claim_read', 'bc_billing_read'],
environments: ['production']
}
];
// Register service account in GCC
async function registerServiceAccount(account: ServiceAccount): Promise<void> {
const response = await gccClient.post('/api/v1/applications', {
clientId: account.clientId,
name: account.name,
description: account.description,
type: 'service',
apiRoles: account.apiRoles.map(role => ({ name: role }))
});
console.log(`Registered service account: ${account.clientId}`);
}typescript
// Service account management
interface ServiceAccount {
clientId: string;
name: string;
description: string;
apiRoles: string[];
environments: string[];
}
const serviceAccounts: ServiceAccount[] = [
{
clientId: 'integration-service-prod',
name: 'Integration Service',
description: 'Backend integration service for policy and claims sync',
apiRoles: ['pc_policy_admin', 'cc_claim_read'],
environments: ['production']
},
{
clientId: 'agent-portal-prod',
name: 'Agent Portal',
description: 'Agent-facing portal application',
apiRoles: ['pc_policy_read', 'pc_submission_handler'],
environments: ['production', 'uat']
},
{
clientId: 'reporting-service',
name: 'Reporting Service',
description: 'Read-only access for reporting',
apiRoles: ['pc_policy_read', 'cc_claim_read', 'bc_billing_read'],
environments: ['production']
}
];
// Register service account in GCC
async function registerServiceAccount(account: ServiceAccount): Promise<void> {
const response = await gccClient.post('/api/v1/applications', {
clientId: account.clientId,
name: account.name,
description: account.description,
type: 'service',
apiRoles: account.apiRoles.map(role => ({ name: role }))
});
console.log(`Registered service account: ${account.clientId}`);
}Step 3: User Role Management in Gosu
步骤3:在Gosu中管理用户角色
gosu
// User role management
package gw.security.roles
uses gw.api.util.Logger
uses gw.pl.persistence.core.Bundle
class RoleManager {
private static final var LOG = Logger.forCategory("RoleManager")
// Assign role to user
static function assignRole(user : User, roleCode : String) {
var role = Role.get(roleCode)
if (role == null) {
throw new IllegalArgumentException("Role not found: ${roleCode}")
}
if (user.hasRole(role)) {
LOG.info("User ${user.UserName} already has role ${roleCode}")
return
}
gw.transaction.Transaction.runWithNewBundle(\bundle -> {
var u = bundle.add(user)
var userRole = new UserRole(bundle)
userRole.User = u
userRole.Role = role
LOG.info("Assigned role ${roleCode} to user ${user.UserName}")
})
}
// Remove role from user
static function removeRole(user : User, roleCode : String) {
var role = Role.get(roleCode)
if (role == null) {
throw new IllegalArgumentException("Role not found: ${roleCode}")
}
gw.transaction.Transaction.runWithNewBundle(\bundle -> {
var u = bundle.add(user)
var userRole = u.Roles.firstWhere(\ur -> ur.Role == role)
if (userRole != null) {
bundle.delete(userRole)
LOG.info("Removed role ${roleCode} from user ${user.UserName}")
}
})
}
// Check if user has permission
static function hasPermission(user : User, permission : String) : boolean {
return user.Roles.hasMatch(\ur ->
ur.Role.Permissions.hasMatch(\p -> p.Code == permission)
)
}
// Get all permissions for user
static function getUserPermissions(user : User) : Set<String> {
var permissions = new HashSet<String>()
user.Roles.each(\ur -> {
ur.Role.Permissions.each(\p -> {
permissions.add(p.Code)
})
})
return permissions
}
}gosu
// User role management
package gw.security.roles
uses gw.api.util.Logger
uses gw.pl.persistence.core.Bundle
class RoleManager {
private static final var LOG = Logger.forCategory("RoleManager")
// Assign role to user
static function assignRole(user : User, roleCode : String) {
var role = Role.get(roleCode)
if (role == null) {
throw new IllegalArgumentException("Role not found: ${roleCode}")
}
if (user.hasRole(role)) {
LOG.info("User ${user.UserName} already has role ${roleCode}")
return
}
gw.transaction.Transaction.runWithNewBundle(\bundle -> {
var u = bundle.add(user)
var userRole = new UserRole(bundle)
userRole.User = u
userRole.Role = role
LOG.info("Assigned role ${roleCode} to user ${user.UserName}")
})
}
// Remove role from user
static function removeRole(user : User, roleCode : String) {
var role = Role.get(roleCode)
if (role == null) {
throw new IllegalArgumentException("Role not found: ${roleCode}")
}
gw.transaction.Transaction.runWithNewBundle(\bundle -> {
var u = bundle.add(user)
var userRole = u.Roles.firstWhere(\ur -> ur.Role == role)
if (userRole != null) {
bundle.delete(userRole)
LOG.info("Removed role ${roleCode} from user ${user.UserName}")
}
})
}
// Check if user has permission
static function hasPermission(user : User, permission : String) : boolean {
return user.Roles.hasMatch(\ur ->
ur.Role.Permissions.hasMatch(\p -> p.Code == permission)
)
}
// Get all permissions for user
static function getUserPermissions(user : User) : Set<String> {
var permissions = new HashSet<String>()
user.Roles.each(\ur -> {
ur.Role.Permissions.each(\p -> {
permissions.add(p.Code)
})
})
return permissions
}
}Step 4: Custom Permission Checks
步骤4:自定义权限校验
gosu
// Custom permission framework
package gw.security.permissions
uses gw.api.util.Logger
uses gw.api.web.SessionUtil
class PermissionChecker {
private static final var LOG = Logger.forCategory("PermissionChecker")
// Check permission with audit logging
static function checkPermission(permission : String) : boolean {
var user = SessionUtil.CurrentUser
if (user == null) {
LOG.warn("Permission check failed: No user in session")
return false
}
var hasPermission = RoleManager.hasPermission(user, permission)
if (!hasPermission) {
LOG.warn("Permission denied: ${permission} for user ${user.UserName}")
auditPermissionDenial(user, permission)
}
return hasPermission
}
// Require permission (throws if denied)
static function requirePermission(permission : String) {
if (!checkPermission(permission)) {
throw new SecurityException("Permission denied: ${permission}")
}
}
// Check entity-level permission
static function canAccessEntity(entity : KeyableBean, operation : String) : boolean {
var user = SessionUtil.CurrentUser
if (user == null) {
return false
}
// Check ownership
if (isOwner(user, entity)) {
return true
}
// Check hierarchical access
if (hasHierarchicalAccess(user, entity)) {
return true
}
// Check role-based access
var permission = "${entity.IntrinsicType.Name}_${operation}"
return checkPermission(permission)
}
private static function isOwner(user : User, entity : KeyableBean) : boolean {
// Check if user created or is assigned to entity
if (entity typeis Policy) {
return entity.CreateUser == user
} else if (entity typeis Claim) {
return entity.AssignedUser == user
}
return false
}
private static function hasHierarchicalAccess(user : User, entity : KeyableBean) : boolean {
// Check organizational hierarchy
if (entity typeis Policy) {
var policyOrg = entity.ProducerCodeOfRecord?.Organization
return user.Organization == policyOrg || isParentOrg(user.Organization, policyOrg)
}
return false
}
private static function auditPermissionDenial(user : User, permission : String) {
// Log to audit trail
gw.api.audit.AuditLogger.log(
"PERMISSION_DENIED",
"User ${user.UserName} denied permission: ${permission}",
user.PublicID
)
}
}gosu
// Custom permission framework
package gw.security.permissions
uses gw.api.util.Logger
uses gw.api.web.SessionUtil
class PermissionChecker {
private static final var LOG = Logger.forCategory("PermissionChecker")
// Check permission with audit logging
static function checkPermission(permission : String) : boolean {
var user = SessionUtil.CurrentUser
if (user == null) {
LOG.warn("Permission check failed: No user in session")
return false
}
var hasPermission = RoleManager.hasPermission(user, permission)
if (!hasPermission) {
LOG.warn("Permission denied: ${permission} for user ${user.UserName}")
auditPermissionDenial(user, permission)
}
return hasPermission
}
// Require permission (throws if denied)
static function requirePermission(permission : String) {
if (!checkPermission(permission)) {
throw new SecurityException("Permission denied: ${permission}")
}
}
// Check entity-level permission
static function canAccessEntity(entity : KeyableBean, operation : String) : boolean {
var user = SessionUtil.CurrentUser
if (user == null) {
return false
}
// Check ownership
if (isOwner(user, entity)) {
return true
}
// Check hierarchical access
if (hasHierarchicalAccess(user, entity)) {
return true
}
// Check role-based access
var permission = "${entity.IntrinsicType.Name}_${operation}"
return checkPermission(permission)
}
private static function isOwner(user : User, entity : KeyableBean) : boolean {
// Check if user created or is assigned to entity
if (entity typeis Policy) {
return entity.CreateUser == user
} else if (entity typeis Claim) {
return entity.AssignedUser == user
}
return false
}
private static function hasHierarchicalAccess(user : User, entity : KeyableBean) : boolean {
// Check organizational hierarchy
if (entity typeis Policy) {
var policyOrg = entity.ProducerCodeOfRecord?.Organization
return user.Organization == policyOrg || isParentOrg(user.Organization, policyOrg)
}
return false
}
private static function auditPermissionDenial(user : User, permission : String) {
// Log to audit trail
gw.api.audit.AuditLogger.log(
"PERMISSION_DENIED",
"User ${user.UserName} denied permission: ${permission}",
user.PublicID
)
}
}Step 5: Row-Level Security
步骤5:行级安全控制
gosu
// Row-level security implementation
package gw.security.rls
uses gw.api.database.Query
uses gw.api.web.SessionUtil
class RowLevelSecurity {
// Apply security filters to queries
static function applySecurityFilter<T extends KeyableBean>(query : Query<T>) : Query<T> {
var user = SessionUtil.CurrentUser
if (user == null || user.hasRole(Role.get("SystemAdmin"))) {
return query // No filtering for system admins
}
var entityType = query.getTargetType()
if (entityType == Policy) {
return applyPolicySecurityFilter(query as Query<Policy>, user) as Query<T>
} else if (entityType == Claim) {
return applyClaimSecurityFilter(query as Query<Claim>, user) as Query<T>
} else if (entityType == Account) {
return applyAccountSecurityFilter(query as Query<Account>, user) as Query<T>
}
return query
}
private static function applyPolicySecurityFilter(
query : Query<Policy>,
user : User
) : Query<Policy> {
// Filter by user's organization or producer code
var userProducerCodes = user.ProducerCodes.map(\pc -> pc.Code)
if (!userProducerCodes.Empty) {
query.join(Policy#ProducerCodeOfRecord)
.compareIn(ProducerCode#Code, userProducerCodes)
}
return query
}
private static function applyClaimSecurityFilter(
query : Query<Claim>,
user : User
) : Query<Claim> {
// Filter by assigned user or group
var userGroups = user.GroupUsers.map(\gu -> gu.Group)
query.or(\orClause -> {
orClause.compare(Claim#AssignedUser, Equals, user)
if (!userGroups.Empty) {
orClause.compareIn(Claim#AssignedGroup, userGroups)
}
})
return query
}
private static function applyAccountSecurityFilter(
query : Query<Account>,
user : User
) : Query<Account> {
// Filter by producer code assignment
var userProducerCodes = user.ProducerCodes.map(\pc -> pc.PublicID)
if (!userProducerCodes.Empty) {
query.subselect(Account#ID, CompareIn,
Query.make(AccountProducerCode)
.compareIn(AccountProducerCode#ProducerCode, userProducerCodes)
.subselect(AccountProducerCode#Account, CompareIn, Account#ID)
)
}
return query
}
}
// Secured query helper
class SecuredQuery {
static function make<T extends KeyableBean>(type : Type<T>) : Query<T> {
var query = Query.make(type)
return RowLevelSecurity.applySecurityFilter(query)
}
}
// Usage
class PolicyService {
static function findPoliciesForCurrentUser() : List<Policy> {
// Automatically applies row-level security
return SecuredQuery.make(Policy)
.compare(Policy#Status, Equals, PolicyStatus.TC_INFORCE)
.select()
.toList()
}
}gosu
// Row-level security implementation
package gw.security.rls
uses gw.api.database.Query
uses gw.api.web.SessionUtil
class RowLevelSecurity {
// Apply security filters to queries
static function applySecurityFilter<T extends KeyableBean>(query : Query<T>) : Query<T> {
var user = SessionUtil.CurrentUser
if (user == null || user.hasRole(Role.get("SystemAdmin"))) {
return query // No filtering for system admins
}
var entityType = query.getTargetType()
if (entityType == Policy) {
return applyPolicySecurityFilter(query as Query<Policy>, user) as Query<T>
} else if (entityType == Claim) {
return applyClaimSecurityFilter(query as Query<Claim>, user) as Query<T>
} else if (entityType == Account) {
return applyAccountSecurityFilter(query as Query<Account>, user) as Query<T>
}
return query
}
private static function applyPolicySecurityFilter(
query : Query<Policy>,
user : User
) : Query<Policy> {
// Filter by user's organization or producer code
var userProducerCodes = user.ProducerCodes.map(\pc -> pc.Code)
if (!userProducerCodes.Empty) {
query.join(Policy#ProducerCodeOfRecord)
.compareIn(ProducerCode#Code, userProducerCodes)
}
return query
}
private static function applyClaimSecurityFilter(
query : Query<Claim>,
user : User
) : Query<Claim> {
// Filter by assigned user or group
var userGroups = user.GroupUsers.map(\gu -> gu.Group)
query.or(\orClause -> {
orClause.compare(Claim#AssignedUser, Equals, user)
if (!userGroups.Empty) {
orClause.compareIn(Claim#AssignedGroup, userGroups)
}
})
return query
}
private static function applyAccountSecurityFilter(
query : Query<Account>,
user : User
) : Query<Account> {
// Filter by producer code assignment
var userProducerCodes = user.ProducerCodes.map(\pc -> pc.PublicID)
if (!userProducerCodes.Empty) {
query.subselect(Account#ID, CompareIn,
Query.make(AccountProducerCode)
.compareIn(AccountProducerCode#ProducerCode, userProducerCodes)
.subselect(AccountProducerCode#Account, CompareIn, Account#ID)
)
}
return query
}
}
// Secured query helper
class SecuredQuery {
static function make<T extends KeyableBean>(type : Type<T>) : Query<T> {
var query = Query.make(type)
return RowLevelSecurity.applySecurityFilter(query)
}
}
// Usage
class PolicyService {
static function findPoliciesForCurrentUser() : List<Policy> {
// Automatically applies row-level security
return SecuredQuery.make(Policy)
.compare(Policy#Status, Equals, PolicyStatus.TC_INFORCE)
.select()
.toList()
}
}Step 6: API Authorization Middleware
步骤6:API授权中间件
typescript
// API authorization middleware
import { Request, Response, NextFunction } from 'express';
interface SecurityContext {
userId: string;
roles: string[];
apiRoles: string[];
organizationId: string;
producerCodes: string[];
}
// Extract security context from JWT
function extractSecurityContext(token: JWTPayload): SecurityContext {
return {
userId: token.sub,
roles: token.roles || [],
apiRoles: token.api_roles || [],
organizationId: token.org_id,
producerCodes: token.producer_codes || []
};
}
// Require specific API role
function requireApiRole(...requiredRoles: string[]) {
return (req: Request, res: Response, next: NextFunction) => {
const context = (req as any).securityContext as SecurityContext;
if (!context) {
return res.status(401).json({ error: 'Unauthorized' });
}
const hasRequiredRole = requiredRoles.some(role =>
context.apiRoles.includes(role)
);
if (!hasRequiredRole) {
return res.status(403).json({
error: 'Forbidden',
message: 'Insufficient API role permissions',
requiredRoles,
userRoles: context.apiRoles
});
}
next();
};
}
// Row-level security filter for API responses
function applySecurityFilter<T>(
data: T[],
context: SecurityContext,
filterFn: (item: T, context: SecurityContext) => boolean
): T[] {
if (context.roles.includes('SystemAdmin')) {
return data;
}
return data.filter(item => filterFn(item, context));
}
// Usage in routes
app.get('/api/policies',
authMiddleware,
requireApiRole('pc_policy_read', 'pc_policy_admin'),
async (req, res) => {
const context = (req as any).securityContext;
let policies = await guidewireClient.getPolicies();
// Apply row-level security
policies = applySecurityFilter(policies, context, (policy, ctx) => {
return ctx.producerCodes.includes(policy.producerCode) ||
ctx.organizationId === policy.organizationId;
});
res.json(policies);
}
);typescript
// API authorization middleware
import { Request, Response, NextFunction } from 'express';
interface SecurityContext {
userId: string;
roles: string[];
apiRoles: string[];
organizationId: string;
producerCodes: string[];
}
// Extract security context from JWT
function extractSecurityContext(token: JWTPayload): SecurityContext {
return {
userId: token.sub,
roles: token.roles || [],
apiRoles: token.api_roles || [],
organizationId: token.org_id,
producerCodes: token.producer_codes || []
};
}
// Require specific API role
function requireApiRole(...requiredRoles: string[]) {
return (req: Request, res: Response, next: NextFunction) => {
const context = (req as any).securityContext as SecurityContext;
if (!context) {
return res.status(401).json({ error: 'Unauthorized' });
}
const hasRequiredRole = requiredRoles.some(role =>
context.apiRoles.includes(role)
);
if (!hasRequiredRole) {
return res.status(403).json({
error: 'Forbidden',
message: 'Insufficient API role permissions',
requiredRoles,
userRoles: context.apiRoles
});
}
next();
};
}
// Row-level security filter for API responses
function applySecurityFilter<T>(
data: T[],
context: SecurityContext,
filterFn: (item: T, context: SecurityContext) => boolean
): T[] {
if (context.roles.includes('SystemAdmin')) {
return data;
}
return data.filter(item => filterFn(item, context));
}
// Usage in routes
app.get('/api/policies',
authMiddleware,
requireApiRole('pc_policy_read', 'pc_policy_admin'),
async (req, res) => {
const context = (req as any).securityContext;
let policies = await guidewireClient.getPolicies();
// Apply row-level security
policies = applySecurityFilter(policies, context, (policy, ctx) => {
return ctx.producerCodes.includes(policy.producerCode) ||
ctx.organizationId === policy.organizationId;
});
res.json(policies);
}
);Role Matrix
角色矩阵
| Role | PolicyCenter | ClaimCenter | BillingCenter |
|---|---|---|---|
| System Admin | Full Access | Full Access | Full Access |
| Underwriter | Submissions, Quotes | Read Only | Read Only |
| Claims Adjuster | Read Only | Claims, Payments | Read Only |
| Billing Admin | Read Only | Read Only | Full Access |
| Agent | Submissions, Read | FNOL Only | Read Only |
| Auditor | Read Only | Read Only | Read Only |
| 角色 | PolicyCenter | ClaimCenter | BillingCenter |
|---|---|---|---|
| 系统管理员 | 完全访问权限 | 完全访问权限 | 完全访问权限 |
| 核保人 | 投保申请、报价 | 只读权限 | 只读权限 |
| 理赔调整员 | 只读权限 | 理赔、支付 | 只读权限 |
| 账单管理员 | 只读权限 | 只读权限 | 完全访问权限 |
| 代理人 | 投保申请、只读 | 仅FNOL(首次通知损失) | 只读权限 |
| 审计员 | 只读权限 | 只读权限 | 只读权限 |
Best Practices
最佳实践
| Practice | Description |
|---|---|
| Least Privilege | Grant minimum necessary permissions |
| Role Separation | Separate roles by function, not convenience |
| Regular Audits | Review role assignments quarterly |
| Service Accounts | Use dedicated accounts for integrations |
| API Role Scoping | Scope API roles to specific endpoints |
| 实践 | 说明 |
|---|---|
| 最小权限原则 | 仅授予完成工作所需的最小权限 |
| 角色分离 | 按职能划分角色,而非出于便利性合并 |
| 定期审计 | 每季度审核角色分配情况 |
| 专用服务账号 | 为集成场景使用专用服务账号 |
| API角色范围限定 | 为API角色限定特定端点的访问权限 |
Output
输出成果
- API role configuration
- Service account setup
- User role management
- Custom permission framework
- Row-level security
- Authorization middleware
- API角色配置
- 服务账号设置
- 用户角色管理模块
- 自定义权限框架
- 行级安全控制实现
- 授权中间件
Resources
参考资源
Next Steps
后续步骤
For migration strategies, see .
guidewire-migration-deep-dive如需了解迁移策略,请查看「guidewire-migration-deep-dive」。