// https://docs.authing.co/v2/reference/sdk-for-node/management/UsersManagementClient.html const { ManagementClient } = require('authing-node-sdk') const managementClient = new ManagementClient({ accessKeyId: '669b25e1731d50c59f5494d1', accessKeySecret: "4cfc095a72a67e22065c97e90054315c", host: 'https://textbook.u2-dev.hep.com.cn', // 应用的认证地址 }) /** * 用户创建前,创建用户至Authing * @desc 仅同步注册信息及密码,资料在afterSave中同步 * @example * 注册: curl -X POST -H "Content-Type: application/json" -H "X-Parse-Application-Id: edu-textbook" -d '{ "username": "333", "password": "333" }' http://127.0.0.1:61337/parse/users * 删除: */ export function defineUserBeforeSave(){ Parse.Cloud.beforeSave("_User", async (request) => { // console.log("UserBeforeSave") request.object = appendUserACL(request.object) let user = request.object; // 仅首次注册/创建用户/修改密码有password属性,同步Authing账号 let password = user?.get("password"); // console.log(password) if(password){ let mobile = user?.get("mobile"); let email = user?.get("email"); let username = user?.get("username"); let externalId = user?.id; let authingUserExists = await findUserByMobileEmailUserName(user) // console.log(authingUserExists) if(authingUserExists?.statusCode==404){ // 创建用户 let newuser = { status:"Activated", password:password, } if(mobile){newuser.phone = mobile} if(email){newuser.email = email} if(username){newuser.username = username} if(externalId){newuser.externalId = externalId} // console.log(newuser) result = await managementClient.createUser(newuser) } if(authingUserExists?.statusCode==200){ let existsUser = authingUserExists?.data; try{ let updateRes = await managementClient.updateUser({ userId:existsUser?.userId, password:password, }) // console.log(result) }catch(err){console.log(err)} } } }); } function appendUserACL(user){ let acl = user?.getACL(); if(!acl) acl = new Parse.ACL(); // 添加superadmin用户的可读可写权限 acl.setRoleWriteAccess("superadmin", true); acl.setRoleReadAccess("superadmin", true); // 添加admin用户的可读可写权限 acl.setRoleWriteAccess("admin", true); acl.setRoleReadAccess("admin", true); // 添加manager用户的可读可写权限 acl.setRoleWriteAccess("manager", true); acl.setRoleReadAccess("manager", true); // 添加公共可读权限 acl.setPublicReadAccess(true); user.setACL(acl); return user } /** * 用户删除前,删除用户从Authing */ export function defineUserAfterDelete(){ Parse.Cloud.afterDelete("_User", async (request) => { let user = request.object; // console.log(user.toJSON()); // console.log(user?.get("password")) try{ let authingUserExists = await findUserByMobileEmailUserName(user) if(authingUserExists?.statusCode==200){ let existsUser = authingUserExists?.data; let deleteRes = await managementClient.deleteUsersBatch({ // 替换用户 ID 数组 userIds: [existsUser.userId], options: { userIdType: "user_id" } }); } }catch(deleteErr){} // 直接给予删除权限 // if(request?.master){ // return await object.destroy({useMasterKey:true}) // } // let requestUser = request.user; // if(!requestUser?.id){ // throw new Parse.Error(206,"Insufficient auth.") // } // let query = new Parse.Query("_Role"); // query.equalTo("users",requestUser) // let roles = await query.find({useMasterKey:true}); // let acl = request.object.getACL(); // if(!acl){ // throw new Parse.Error(206,"Object has no ACL.") // } // if(acl.getWriteAccess(requestUser)){ // return await request.object.destroy({useMasterKey:true}) // }else{ // let hasPermission = roles.some(role=>acl.getRoleWriteAccess(role.getName())) // if(hasPermission) { // return await request.object.destroy({useMasterKey:true}) // } // throw new Parse.Error(206,"Insufficient auth.") // } }); } /** * 用户保存后同步数据至Authing */ export function defineUserAfterSave(){ Parse.Cloud.afterSave("_User", async (request) => { // console.log("save _User",request?.object?.id) let query = new Parse.Query("Profile"); query.equalTo("user",request?.object?.id) let profile = await query.first(); syncUserProfileToAuthing(request?.object,profile) }); Parse.Cloud.afterSave("Profile", async (request) => { // console.log("save Profile",request?.object?.id) let query = new Parse.Query("Profile"); let userPointer = request?.object?.get("user") query.include("user"); // console.log(userPointer) profile = await query.get(request?.object?.id,{useMasterKey:true}); syncUserProfileToAuthing(profile.get("user"),profile) appandUserToRole(profile.get("user")?.toPointer() || userPointer,profile?.get("identity")) }); } // 同步Profile角色身份 var roleNameMap = { "国家级管理员":"superadmin", "工作联系人":"admin", "高校联系人":"manager", } async function appandUserToRole(user,roleName) { // console.log(user,roleName) roleName = roleNameMap[roleName] || roleName let id = user?.id || user?.objectId if(!id || !roleName) return let userObj = new Parse.User(); userObj.id = id; let query = new Parse.Query(Parse.Role); query.equalTo("name", roleName); try{ let role = await query.first({ useMasterKey: true }); // console.log(role?.toJSON()) if (role?.toJSON()?.name) { let usersRelation = role.relation("users"); usersRelation.add(userObj); await role.save(null, { useMasterKey: true }); let users = await usersRelation.query().find({ useMasterKey: true }); // console.log('Users in role after addition:', users.map(u => u.toJSON())); } }catch(err){ console.error(err) } } /** * 查询用户 * @param {*} user * @returns * 不存在: * { statusCode: 404, apiCode: 2004, message: '用户不存在', requestId: 'e59cb407-f2d9-4bd8-ac93-d2dbc8d6ab72' } { statusCode: 200, message: '', data: { userId: '669676e5a3a9ac870bfff2a3', createdAt: '2024-07-16T13:34:29.789Z', updatedAt: '2024-07-16T13:34:29.789Z', status: 'Activated' } } */ async function findUserByMobileEmailUserName(user){ let mobile = user?.get("mobile"); let email = user?.get("email"); let username = user?.get("username"); let externalId = user?.id; let result; if(email){ try{ result = await managementClient.getUser({userIdType:`email`,userId:email}) // console.log(email,result) }catch(err){} } if(mobile&&(!result || result?.statusCode==404)){ try{ result = await managementClient.getUser({userIdType:`phone`,userId:mobile}) // console.log(mobile,result) }catch(err){} } if(username&&(!result || result?.statusCode==404)){ try{ result = await managementClient.getUser({userIdType:`username`,userId:username}) // console.log("username",username,result) }catch(err){} } if(externalId&&(!result || result?.statusCode==404)){ try{ result = await managementClient.getUser({userIdType:`external_id`,userId:externalId}) // console.log(externalId,result) }catch(err){} } return result } async function syncUserProfileToAuthing(user,profile){ if(!user?.id) return let userInfo = user.toJSON(); userInfo = fixJsonFileds(userInfo) if(profile?.id){ let pjson = profile.toJSON(); delete pjson.objectId; pjson= fixJsonFileds(pjson) Object.keys(pjson).forEach(key=>{ userInfo[key] = pjson[key] }) } // 映射对应字段 userInfo.company = userInfo.companyName delete userInfo.companyName userInfo.userType = userInfo.identity delete userInfo.identity userInfo.userId = userInfo.objectId let authingUserExists = await findUserByMobileEmailUserName(user) if(authingUserExists?.statusCode==200){ let existsUser = authingUserExists?.data; userInfo.userId = existsUser.userId } delete userInfo.objectId userInfo.identifyStatus = userInfo.accountState // 自定义数据全量同步 userInfo.customData = JSON.parse(JSON.stringify(userInfo)) // { // identifyStatus : userInfo.accountState // } // console.log(userInfo) // 同步数据至Authing用户池 let result try{ result = await managementClient.updateUser(userInfo) // console.log(result) }catch(err){console.log(err)} } function fixJsonFileds(json){ // Parse独有关系数据 delete json.ACL delete json.className delete json.sessionToken delete json.company delete json.user delete json.createdAt delete json.updatedAt // 来自Authing的数据 delete json?.loginsCount delete json?.lastIP delete json?.lastLogin return json }