authing
从 2025 年 2 月 26 日起,Authing 公有云免费用户池将享受每天 50 次邮件发送额度,付费用户池不受影响,使用自定义邮件服务商的用户池不受影响。如有问题请联系客服 400-888-2106。
authing
预约咨询
音乐平台项目实例
本项目将以一个 Github 上开源的音乐管理系统为例,介绍如何接入 Authing 服务到一个现成系统,帮助你快速开启数字化征程~

项目介绍

引用的开源项目地址:

Gitee:https://gitee.com/Yin-hongwei/music-website

Github:https://github.com/Yin-Hongwei/music-website

项目前后端分离,前端采用 Vue3 + Typescript,后端采用 SpringBoot,均是具有代表性的技术栈。

项目说明文档中已经详细的阐述了如何部署到本地,此处仅补充说明:

1. 通过百度云盘下载项目的音乐、图片资源(非必要)

2. 修改配置文件(Mysql,Redis)

3. 分别启动前后端服务(前端分为管理端和用户端,共三个服务)

4. 两个前端项目依赖安装建议跟随说明文档采用 yarn 命令安装依赖

项目仅作示例展示用,接下来将具体介绍如何接入 Authing 服务,有多种方式,本文侧重点在于介绍通过不改变原本项目前端 UI,而在后端「调用 SDK 」的方式。

预备知识

如果你还没有用过 Authing,可以点击这里查看如何创建一个自己的应用。

对 Authing 的任何名词/概念有疑问:https://docs.authing.co/v2/concepts/

接下来,假设你已经对 Authing 有初步了解,且在 Authing 控制台创建了一个自己的应用。

全局配置

首先要在 pom.xml 文件中引入 Authing 提供的 SDK 依赖:
<dependency> <groupId>cn.authing</groupId> <artifactId>authing-java-sdk</artifactId> <version>{LATEST_VERSION}</version> </dependency>
最新的版本号 LATEST_VERSION 需要你根据 groupId 和 artifactId 自行到 Maven 官网查找。

引入 Authing 提供的 SDK 之后,要获取Authing 服务最核心的认证侧类 AuthenticationClient管理侧类 ManagementClient,通过调用这两个类中封装好的方法,就可以使用 Authing 提供的服务。

可以通过在后端项目中添加 config 配置类,将AuthenticationClientManagementClient 作为 Bean 注入到 Spring之中,此后在各处仅需获取 Bean 并使用即可(例如:@Autowired)。

具体地,在项目主程序同级目录下创建 config 文件夹,在该文件夹中新建 AuthingConfig 类。

示例代码如下:
@Configuration public class AuthingConfig { @Bean @Scope("prototype") public AuthenticationClient authenticationClient() throws IOException, ParseException { //在构造函数中分别填入自己的 App ID、App Secret、APP Host。 AuthenticationClientOptions options = new AuthenticationClientOptions(); options.setAppId("YOUR_APP_ID"); options.setAppSecret("YOUR_APP_SECRET"); options.setAppHost("YOUR_APP_HOST"); AuthenticationClient client = new AuthenticationClient(options); return client; } @Bean @Scope("prototype") public ManagementClient managementClient() { //在构造函数中分别填入自己的 用户池 ID、用户池 Secret、APP Host ManagementClientOptions options = new ManagementClientOptions(); options.setAccessKeyId("YOUR_APP_ID"); options.setAccessKeySecret("YOUR_APP_SECRET"); options.setHost("YOUR_APP_HOST"); ManagementClient client = new ManagementClient(options); return client; } }

如果你不知道如何获取这些数据:

App ID、App Secret、APP Host:https://docs.dev.authing-inc.co/v2/guides/faqs/get-app-id-and-secret.html

用户池 ID、用户池 Secret:https://docs.authing.co/v2/guides/faqs/get-userpool-id-and-secret.html

登录/注册

1. 登录
刚初始化的系统建议自己在 Authing 控制台手动创建一个「超级管理员」账号用于登录
管理端前端登录界面展示:
authing
管理端后端 AdminController 中获取用户名和密码参数,并调用 Authing 提供的 SDK
LoginTokenRespDto loginTokenRespDto = authenticationClient.signInByUsernamePassword( username, password, new SignInOptionsDto() );
SignInOptionsDto 参数非必需,其含义可以在后文补充说明的连接中自行下载并阅读源码。 LoginTokenRespDto 为 Authing 提供的 SDK 返回的统一格式的对象,包含的属性如下图所示:
authing

重点关注:

statusCode,代表请求成功/失败
data,请求返回的数据
有了这些数据可以进一步进行登录验证的判断:
if (loginTokenRespDto.getStatusCode() == 200) { return new SuccessMessage("登录成功", loginTokenRespDto.getData().getAccessToken()).getMessage(); } else { // 该项目未进行错误码区分,故此处仅传递错误信息; // Authing 定义的错误码可以通过 loginTokenRespDto.getApiCode() 获取 return new ErrorMessage(loginTokenRespDto.getMessage()).getMessage(); }

此处登录成功后返回的 data 中会包含 accessToken,该字符串是 Authing 的接口访问凭据,建议将其返回到前端,存储在 cookie 中,之后后端接受的部分请求将从 cookie 中获取 accessToken 并对其进行验证。

注意:前端保存和后端读取要注意区分管理端和用户端的 cookie 名称,即区分不同端登录的用户。

此处给出一种前端保存 cookie 的办法的代码:

命令行
npm install vue-cookies --save
main.ts
import VueCookies from 'vue-cookies' const app = createApp(App); app.config.globalProperties.$cookies = VueCookies;
Login.vue
import { getCurrentInstance } from "vue"; let internalInstance = getCurrentInstance(); let cookies = internalInstance.appContext.config.globalProperties.$cookies; async function submitForm() { let params = new URLSearchParams(); params.append("username", ruleForm.username); params.append("password", ruleForm.password); const result = (await HttpManager.getLoginStatus(params)) as ResponseBody; (proxy as any).$message({ message: result.message, type: result.type, }); if (result.success){ cookies.set("accessToken",result.data); routerManager(RouterName.Info, { path: RouterName.Info }); } }
用户端登录逻辑和管理端类似,只是 Controller不同,此处仅展示前端界面截图:
authing
2. 登出
管理端前端界面:
authing
后端 AdminController 代码:
@PostMapping("admin/logout") public Object logout(@CookieValue(value = "manageAccessToken",required = false) String accessToken){ if(StrUtil.isBlank(accessToken)){ return new ErrorMessage("accessToken 已失效,请重新登录").getMessage(); } Boolean flag = authenticationClient.revokeToken(accessToken); if(flag){ return new SuccessMessage<>("退出登录").getMessage(); }else{ return new ErrorMessage("撤销accessToken出错").getMessage(); } }
用户端登出逻辑和管理端类似,此处仅展示前端界面截图:
authing
3. 注册

需要注意的是,该项目前端中管理端不提供注册功能,只有用户端可以注册。

用户端前端注册界面:
authing
后端 Controller 代码:
// 创建注册配置项 signUpDto SignUpDto signUpDto = new SignUpDto(); // 设置连接方式 signUpDto.setConnection(SignUpDto.Connection.PASSWORD); // 设置账号密码到 passwordDto SignUpByPasswordDto passwordDto = new SignUpByPasswordDto(); passwordDto.setUsername(username); passwordDto.setPassword(password); // 设置 passwordDto 到 signUpDto signUpDto.setPasswordPayload(passwordDto); // 设置其他信息到 profileDto SignUpProfileDto profileDto = new SignUpProfileDto(); // 性别的额外逻辑处理 if ("0".equals(sex)) { profileDto.setGender(SignUpProfileDto.Gender.F); } else if ("1".equals(sex)) { profileDto.setGender(SignUpProfileDto.Gender.M); } else { profileDto.setGender(SignUpProfileDto.Gender.U); } profileDto.setBirthdate(birth); profileDto.setAddress(location); profileDto.setPhoto(avator); profileDto.setProfile(introduction); // 设置 profileDto 到 signUpDto signUpDto.setProfile(profileDto); // 调用 authing 接口 (注册用户) UserSingleRespDto userSingleRespDto = authenticationClient.signUp(signUpDto);

可以看出 Authing 提供的 SDK 包含了该项目用户所需的全部属性,可以完全替代原本的后端接口,当然,有些地方需要你根据实际项目作额外的逻辑处理。

需要补充的一点是,原示例系统中,用户注册时需要填手机号和邮箱,用户实体类中也包含这两条属性,此处删除。因为 Authing 服务将手机号/邮箱和用户进行绑定时,会向手机号/邮箱发送验证邮件,用户需在规定时间内填写验证码才能通过验证并成功绑定。

如业务需要,此处提供一些 JAVA SDK:

绑定邮箱:AuthenticationClient.bindEmail()
绑定手机号:AuthenticationClient.bindPhone()
修改用户信息:AuthenticationClient.updateProfile()

更多 JAVA SDK 可以自行查看 AuthenticationClient/ManagementClient 源码,更底层的开放 API 可以看Authing 开放 API文档。

4. Authing Guard 登录/注册
相比原用户端界面增加了如下两个入口:
authing
内嵌使用,即将 Authing 的登录窗挂载到你的 dom 节点,效果如下:
authing
托管使用,即跳转到 Authing 管理的前端页面进行登录,登录完成后回调回自己的服务,效果如下:
authing

使用 Guard 进行登录需要注意以下几点:

关于 accessToken 的获取方式改变:Guard 登录成功后返回的用户信息中包含了属性名为 token 的 ID Token,然后参考文档使用 ID Token 换取 Access Token,自己换取 AccessToken。示例代码中已经做好,但你仍需要参考该文档进行控制台的额外配置。
为了兼容原本的账号密码登录,需要进行额外逻辑处理:作普通登录和 Guard 登录、登出的判断。

用户管理

上面介绍登录/注册时,细心的你可能注意到了,只有用户端可以进行注册,管理端是无法进行注册的。那么怎么解决管理端的账号问题呢?

首先,系统会默认创建一个超级管理员角色,此处以 superAdmin 为例,给出在 Authing 的控制台创建角色的示例,当然你也可以自己用其他方式(比如调用 SDK)解决这个问题。

当然,Authing 控制台此处也可以创建更多用户

首先打开你的应用,找到用户管理 - 用户列表 - 创建用户,点击(示图中已经创建完成)
authing
弹框如下:
authing

建议根据你所使用的系统中的实际情况来决定创建方式,示例系统中仅有用户名+密码的方式,所以此处使用用户名方式创建 superAdmin 用户。

这样你就可以登录管理端了。你可能会有另一个疑问,那么用户端创建的用户难道也可以登录管理端吗?现在用户端和管理端的用户不是放在一起了吗?没错,用户端和管理端的用户确实放在了一起(建议如此,也可以不放在一起)。但是我们可以给用户赋予不同角色,来区分用户端和管理端的用户,这点会在下文角色管理详细说明。

管理端可以完成的操作如下:
登录后,界面如下:
authing

示例系统中,可以对用户进行列表展示和删除/批量删除的操作,下面展示使用 Authing 提供的 SDK 代替原本的代码:

列表展示
后端 ConsumerController 代码:
@RequestMapping(value = "/user", method = RequestMethod.GET) public Object allUser() { int page = 1, limit = 10; List<UserDto> userList = new ArrayList<>(); ListUsersRequestDto listUsersRequestDto = new ListUsersRequestDto(); ListUsersOptionsDto optionsDto = new ListUsersOptionsDto(); PaginationDto paginationDto = new PaginationDto(); paginationDto.setPage(page); paginationDto.setLimit(limit); optionsDto.setPagination(paginationDto); listUsersRequestDto.setOptions(optionsDto); // 调用 authing 接口 (获取所有用户列表) UserPaginatedRespDto users = managementClient.listUsers(listUsersRequestDto); userList.addAll(users.getData().getList()); // 循环分页处理, 返回全量数据 while (users.getData().getTotalCount() - userList.size() > 0) { paginationDto.setPage(++page); paginationDto.setLimit(limit); optionsDto.setPagination(paginationDto); listUsersRequestDto.setOptions(optionsDto); // 调用 authing 接口 (再次分页获取数据) users = managementClient.listUsers(listUsersRequestDto); userList.addAll(users.getData().getList()); } List<Consumer> consumers = convertConsumers(userList); return new SuccessMessage<List<Consumer>>(null, consumers).getMessage(); }

需要注意的是, Authing 提供的 SDK 中默认有分页的功能,将数据按照 page=1,limit=10 来返回,示例代码中,由于前端原本代码中自带分页功能,故将其合并到了一个 List 之中。

还有一点需要注意,要将 Authing 提供的 SDK 中返回的 UserDto 对象映射成你实际的用户对象。

删除
后端 ConsumerController 代码:
@GetMapping("/user/delete") public Object deleteUserByAdmin(HttpServletRequest req){ String id = req.getParameter("id"); DeleteUsersBatchDto deleteDto = new DeleteUsersBatchDto(); deleteDto.setUserIds(Collections.singletonList(id)); // 调用 authing 接口 (根据 userId 删除用户) boolean res = managementClient.deleteUsersBatch(deleteDto).getData().getSuccess(); if (res) { return new SuccessMessage<Null>("删除成功").getMessage(); } else { return new ErrorMessage("删除失败").getMessage(); } }
批量删除

原系统在前端采用循环调用删除来实现。

用户端可以完成的操作如下:
修改个人资料
前端界面:
authing
后端 ConsumerController 代码:
@ResponseBody @RequestMapping(value = "/user/update", method = RequestMethod.POST) public Object updateUserMsg(HttpServletRequest req) { String id = req.getParameter("id").trim(); String username = req.getParameter("username").trim(); String sex = req.getParameter("sex").trim(); String birth = req.getParameter("birth").trim(); String introduction = req.getParameter("introduction").trim(); String location = req.getParameter("location").trim(); // 更新字段填充 UpdateUserReqDto updateDto = new UpdateUserReqDto(); updateDto.setUserId(id); updateDto.setUsername(username); updateDto.setBirthdate(birth); updateDto.setProfile(introduction); updateDto.setAddress(location); if ("0".equals(sex)) { updateDto.setGender(UpdateUserReqDto.Gender.F); } else if ("1".equals(sex)) { updateDto.setGender(UpdateUserReqDto.Gender.M); } else { updateDto.setGender(UpdateUserReqDto.Gender.U); } // 调用 authing 接口 UserSingleRespDto updateUser = managementClient.updateUser(updateDto); if (updateUser.getStatusCode() == 200) { return new SuccessMessage<Null>("修改成功").getMessage(); } else { return new ErrorMessage("修改失败").getMessage(); } }
更新密码:
前端界面:
authing
后端 ConsumerController 代码:
@ResponseBody @RequestMapping(value = "/user/updatePassword", method = RequestMethod.POST) public Object updatePassword(HttpServletRequest req,@CookieValue("userAccessToken") String accessToken) { // 配置 accessToken authenticationClient.setAccessToken(accessToken); // String id = req.getParameter("id").trim(); // String username = req.getParameter("username").trim(); String old_password = req.getParameter("old_password").trim(); String password = req.getParameter("password").trim(); UpdatePasswordDto updatePasswordDto = new UpdatePasswordDto(); updatePasswordDto.setOldPassword(old_password); updatePasswordDto.setNewPassword(password); updatePasswordDto.setPasswordEncryptType(UpdatePasswordDto.PasswordEncryptType.NONE); CommonResponseDto commonResponseDto = authenticationClient.updatePassword(updatePasswordDto); if (commonResponseDto.getStatusCode() == 200) { return new SuccessMessage<Null>("密码修改成功").getMessage(); } else { return new ErrorMessage(commonResponseDto.getMessage()).getMessage(); } }

此处 updatePassword() 调用的前提是在 authenticationClient 中配置 accessToken(之后也会有类似情况),因为 accessToken 携带了用户信息,所以不再需要传递id、username 等信息,仅需要旧密码和新密码,就可以修改密码。

自我注销
前端界面:
authing
后端 ConsumerController 代码:
@RequestMapping(value = "/user/deleteSelf", method = RequestMethod.POST) public Object deleteUserBySelf(HttpServletRequest req,@CookieValue("userAccessToken") String accessToken) { // String id = req.getParameter("id"); String password = req.getParameter("password"); authenticationClient.setAccessToken(accessToken); VerifyDeleteAccountRequestDto verifyDeleteAccountRequestDto = new VerifyDeleteAccountRequestDto(); verifyDeleteAccountRequestDto.setVerifyMethod(VerifyDeleteAccountRequestDto.VerifyMethod.PASSWORD); DeleteAccountByPasswordDto deleteAccountByPasswordDto = new DeleteAccountByPasswordDto(); deleteAccountByPasswordDto.setPassword(password); verifyDeleteAccountRequestDto.setPasswordPayload(deleteAccountByPasswordDto); // 调用 authing 接口 VerifyDeleteAccountRequestRespDto verifyDeleteAccountRequestRespDto = authenticationClient.verifyDeleteAccountRequest(verifyDeleteAccountRequestDto); if(verifyDeleteAccountRequestRespDto.getStatusCode() != 200){ return new ErrorMessage(verifyDeleteAccountRequestRespDto.getMessage()).getMessage(); } String deleteAccountToken = verifyDeleteAccountRequestRespDto.getData().getDeleteAccountToken(); DeleteAccounDto deleteAccounDto = new DeleteAccounDto(); deleteAccounDto.setDeleteAccountToken(deleteAccountToken); // 调用 authing 接口 authenticationClient.deleteAccount(deleteAccounDto); return new SuccessMessage<>("删除成功").getMessage(); }
注意区分用户自我注销和管理员删除的区别,本质在于权限,体现在调用的是 authenticationClient 还是 managementClient

角色管理

书接上文,管理端和用户端账号的区分,依赖于角色,下面将介绍示例代码中对于整个系统的角色划分,当然你可以自定义。最初,我们给系统创建了一个 superAdmin 用户,现在,我们赋予它 superAdmin 角色。

用 superAdmin 账号登录管理端,找到角色管理 - 新增角色,点击(示图中已经完成创建)。
authing
弹窗如下:
authing
新增角色 RoleController 代码:
@PostMapping("role/add") public Object addRole(HttpServletRequest req){ String code = req.getParameter("code").trim(); String description = req.getParameter("description").trim(); CreateRoleDto createRoleDto = new CreateRoleDto(); createRoleDto.setCode(code); createRoleDto.setDescription(description); createRoleDto.setNamespace(authenticationClient.getOptions().getAppId()); // 调用 authing 接口 RoleSingleRespDto roleSingleRespDto = managementClient.createRole(createRoleDto); if(roleSingleRespDto.getStatusCode() == 200){ return new SuccessMessage<>("添加成功").getMessage(); }else { return new ErrorMessage(roleSingleRespDto.getMessage()).getMessage(); } }
删除角色 RoleController 代码:
@GetMapping("role/delete") public Object deleteRole(HttpServletRequest req){ String code = req.getParameter("code"); DeleteRoleDto deleteRoleDto = new DeleteRoleDto(); // 支持批量删除 List<String> codeList = new ArrayList<>(); codeList.add(code); deleteRoleDto.setCodeList(codeList); deleteRoleDto.setNamespace(authenticationClient.getOptions().getAppId()); // 调用 authing 接口 IsSuccessRespDto isSuccessRespDto = managementClient.deleteRolesBatch(deleteRoleDto); if(isSuccessRespDto.getStatusCode() == 200){ return new SuccessMessage<>("删除成功").getMessage(); }else { return new ErrorMessage(isSuccessRespDto.getMessage()).getMessage(); } }

批量删除原系统在前端采用循环调用删除来实现。

之后,依次创建你所需要的角色,此示例系统中,给定四个角色如下:
authing

其中,superAdmin 是系统的第一个默认超级管理员账号;在用户端创建的账号,创建成功后默认赋予 user 角色,仅可以登录用户端;vip 角色,也是仅可以登录用户端,但由于示例系统是音乐系统,此处给出区别与普通角色的 vip 角色;admin 角色,可以登录用户端和管理端。

一个账号可以拥有多个角色;默认对外不显示 superAdmin 角色的存在;账号不允许撤回 user 角色。

后端 AdminController 代码添加:
//判断用户是不是管理员 boolean isAdmin = false; for(String role:roleList){ if(RoleCodeEnum.ADMIN.getValue().equals(role) || RoleCodeEnum.SUPER_ADMIN.getValue().equals(role)){ isAdmin = true; break; } } if (loginTokenRespDto.getStatusCode() == 200) { if(isAdmin){ // 只有请求成功且是管理员才能登录后台系统,同时将 accessToken 返回到前端 return new SuccessMessage<String>("登录成功",loginTokenRespDto.getData().getAccessToken()).getMessage(); }else{ return new ErrorMessage("只有管理员才能登录后台管理系统").getMessage(); } } else { // 该项目未进行错误码区分,故此处仅传递错误信息;Authing 定义的错误码可以通过 loginTokenRespDto.getApiCode() 获取 return new ErrorMessage(loginTokenRespDto.getMessage()).getMessage(); }
此处要修改之前登录的代码逻辑,需要判断用户角色是否是 admin 或者 superAdmin。
拥有 superAdmin 或者 admin 角色的账号登录管理端之后,可以修改用户的角色:
authing
弹窗如下:
authing
前端代码: ConsumerPage.vue
<!-- template部分 --> <el-dialog title="修改角色" v-model="roleVisible" @close="roleVisible = false" width="300px" center> <el-form label-width="60px" :model="roleEditForm" :rules="roleRule"> <el-form-item prop="roleCodes"> <el-select v-model="roleEditForm.roleCodes" multiple placeholder="请选择角色"> <el-option v-for="item in roleEditForm.roleOptions" :key="item.code" :label="item.code" :value="item.code" ></el-option> </el-select> </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> <el-button @click="roleVisible = false">取 消</el-button> <el-button type="primary" @click="saveRoleEdit">确 定</el-button> </span> </template> </el-dialog> /** * typescript部分 */ const roleVisible = ref(false); const editRoleCode = ref("-1"); const containsUser = (rule,value,callback) => { if(!value.includes("user")){ callback(new Error("不能删除基本 user 角色")); }else{ callback(); } } const roleRule = reactive({ roleCodes: [{ required: true, validator: containsUser, trigger: "change"}], }); const roleEditForm = reactive({ roleCodes:[], roleOptions:[], }) getRoleOptions(); async function getRoleOptions(){ try{ const result = (await HttpManager.getAllRoleWithOutSuperAdmin()) as ResponseBody; roleEditForm.roleOptions = result.data; (proxy as any).$message({ message: result.message, type: result.type, }); if (result.success) getData(); }catch(error){ console.error(error); } } function changeRole(row){ editRoleCode.value = row.id; roleEditForm.roleCodes = row.roleCodes; roleVisible.value = true; } async function saveRoleEdit() { try { let params = { userId: editRoleCode.value, codeList: roleEditForm.roleCodes } const result = (await HttpManager.changeRole(params)) as ResponseBody; (proxy as any).$message({ message: result.message, type: result.type, }); if (result.success) getData(); roleVisible.value = false; } catch (error) { console.error(error); } }
后端 ConsumerController 代码:
@PostMapping("user/changeRole") public Object changeRole(@RequestBody UserRoleParam param){ String userId = param.getUserId(); List<String> codeList = param.getCodeList(); // 检查是否删除了 user 角色 if(!codeList.contains(RoleCodeEnum.USER.getValue())){ return new ErrorMessage("不允许删除基本的 user 角色").getMessage(); } // 获取全部用户角色 ListRolesDto listRolesDto = new ListRolesDto(); listRolesDto.setNamespace(authenticationClient.getOptions().getAppId()); // 调用 authing 接口 RolePaginatedRespDto rolePaginatedRespDto = managementClient.listRoles(listRolesDto); List<RoleDto> roleDtoList = rolePaginatedRespDto.getData().getList(); // 设置清空和添加的共同目标 —— 用户 List<TargetDto> target = new ArrayList<>(); TargetDto targetDto = new TargetDto(); targetDto.setTargetType(TargetDto.TargetType.USER); targetDto.setTargetIdentifier(userId); target.add(targetDto); // 清空该用户角色 for(RoleDto roleDto:roleDtoList){ RevokeRoleDto revokeRoleDto = new RevokeRoleDto(); revokeRoleDto.setTargets(target); revokeRoleDto.setNamespace(authenticationClient.getOptions() .getAppId()); // code 不同 revokeRoleDto.setCode(roleDto.getCode()); // 调用 authing 接口 IsSuccessRespDto isSuccessRespDto = managementClient.revokeRole(revokeRoleDto); if(isSuccessRespDto.getStatusCode() != 200){ return new ErrorMessage("修改角色失败").getMessage(); } } // 添加角色 for(String code:codeList){ AssignRoleDto assignRoleDto = new AssignRoleDto(); assignRoleDto.setTargets(target); assignRoleDto.setNamespace(authenticationClient.getOptions() .getAppId()); assignRoleDto.setCode(code); // 调用 authing 接口 IsSuccessRespDto isSuccessRespDto = managementClient.assignRole(assignRoleDto); if(isSuccessRespDto.getStatusCode() != 200){ return new ErrorMessage("修改角色失败").getMessage(); } } return new SuccessMessage<>("修改成功").getMessage(); }

资源管理与授权

首先,介绍 Authing 定义的资源:

Authing 中的资源是你的业务系统中实际资源的标识符,一个资源可以是你的业务系统中的某一个实体,如 Order,我们也可以对 order 设定一个具体的操作,如:order:read;资源也可以是 UI 界面上的某一个菜单,一个按钮。资源的具体定义可以参考文档,当你把所有业务资源都在 Authing 中创建以后,就能控制对它们的访问、修改等权限。

如何在 Authing 控制台创建资源:

此处以及以下截图为旧版控制台
authing

记得权限分组选中自己创建的应用。

弹窗如下:
authing
1. 文件
你可以自定义资源,此处文件资源示例为歌单,定义如下:
authing
之后,可以对该资源进行授权,点击资源管理旁边的授权管理,再点击授权按钮。
authing
如图所示,只授权 user 角色访问 SongListIds 为 1、3、5、7、9 (Authing 控制台中要以下划线分割)的歌单(或者拒绝其访问偶数 id 的歌单),授权 vip 角色访问全部歌单。同理可以授权其他资源给用户、角色等……
authing
仅拥有 user 角色的用户访问 2 号歌单效果图:
authing
访问 3 号歌单,不会报错,且能看到数据:
authing
后端 ListSongController 代码:
@RequestMapping(value = "/listSong/detail", method = RequestMethod.GET) public Object listSongOfSongId(HttpServletRequest req, HttpSession session) { String songListId = req.getParameter("songListId"); // 获取歌单的 ids List<String> resources = getResources(session); if (resources.contains("*") || resources.contains(songListId)) { return new SuccessMessage<List<ListSong>>("添加成功", listSongService.listSongOfSongId(Integer.parseInt(songListId))) .getMessage(); } return new ErrorMessage("抱歉, 非 VIP 用户无法享用 VIP 歌单~").getMessage(); }
具体获取资源代码:
/** * 获取资源列表 * @param session * @return */ private List<String> getResources(HttpSession session) { GetUserRolesDto getUserRolesDto = new GetUserRolesDto(); getUserRolesDto.setNamespace(namespace); getUserRolesDto.setUserId(session.getAttribute("username").toString()); getUserRolesDto.setUserIdType(ResignUserReqDto.UserIdType.USERNAME.getValue()); // 调用 authing 接口 (获取用户的角色) RolePaginatedRespDto userRoles = managementClient.getUserRoles(getUserRolesDto); List<RoleDto> roles = userRoles.getData().getList(); List<String> resources = new ArrayList<>(); roles.forEach((dto) -> { GetRoleAuthorizedResourcesDto resourcesDto = new GetRoleAuthorizedResourcesDto(); resourcesDto.setNamespace(namespace); resourcesDto.setCode(dto.getCode()); resourcesDto.setResourceType(ResourceItemDto.ResourceType.DATA.getValue()); // 调用 authing 接口 (获取角色的资源) RoleAuthorizedResourcePaginatedRespDto roleAuthorizedResources = managementClient.getRoleAuthorizedResources(resourcesDto); List<RoleAuthorizedResourcesRespDto> list = roleAuthorizedResources.getData().getList(); List<String> resource = new ArrayList<>(); // 对资源做处理,获取歌单 ID list.stream().forEach(item -> { String[] ids = item.getResourceCode().split(":")[1].split("_"); resource.addAll(Arrays.asList(ids)); }); resources.addAll(resource); }); return resources; }
身份顾问在线解答
当前在线
如何打造完整的身份体系?
立即沟通
authing
添加企业微信,领取行业资料
authing
authing
下载 Authing 令牌,体验快速登录认证!
免费使用
在线咨询
电话咨询