介绍
目前正在着手开发一款功能全面的接口自动化测试平台,该平台将涵盖登录、用户管理、权限控制、项目管理、用例管理、测试数据管理、测试报告生成、任务调度、缺陷跟踪以及系统配置等多个核心模块。为了区分各个用户的角色,我们将平台用户分为四种角色:管理员、测试经理、测试工程师、数据管理员。
用户角色功能详解
技术选型
-
后端:采用Java作为主要开发语言。
-
前端:使用VUE框架进行界面展示。
-
行为记录:Java服务负责记录用户行为,而VUE则用于展示这些行为记录。
数据库表设计
我们需要设计4张表,用户表、角色表、菜单表、角色与菜单关联表
用户表: 记录用户信息,需要有一个role_id,对应角色表。
角色表: 记录角色信息。
菜单表: 记录菜单信息,和功能模块的一级接口路径。
角色与菜单关联表: 记录角色id和菜单id对应关系。
接口设计
接口路径采用双层路径,第一层为功能模块标识、第二层为接口功能标识,如下:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
UserService userService;
@PostMapping("/add")
public ResponseEntity<Map<String, Object>> addUser(@RequestBody @Validated UserDTO userDTO, HttpServletRequest request) {
return userService.addUser(userDTO, request);
}
@PostMapping("/list")
public ResponseEntity<Map<String, Object>> userList(@RequestBody UserDTO userDTO, HttpServletRequest request) {
return userService.userList(userDTO, request);
}
@PostMapping("/update")
public ResponseEntity<Map<String, Object>> update(@RequestBody UserDTO userDTO, HttpServletRequest request) {
return userService.update(userDTO, request);
}
@DeleteMapping("/delete")
public ResponseEntity<Map<String, Object>> delete(@RequestBody UserDTO userDTO, HttpServletRequest request) {
return userService.delete(userDTO, request);
}
}
我们通过接口路径中的user来进行权限管理,只有有user权限的用户,才能访问接口。
拦截器实现
通过实现HandlerInterceptor
接口中的preHandle
方法,我们能够在接口调用前进行拦截。当用户没有调用接口权限时,直接返回暂无访问权限的提示:
@Component
public class MyInterceptor implements HandlerInterceptor {
public static final Logger logger = LoggerFactory.getLogger(MyInterceptor.class);
@Autowired
RedisUtil redisUtil;
@Autowired
User user;
@Autowired
UserLogService userLogService;
@Override
public boolean preHandle(HttpServletRequest request, @Nonnull HttpServletResponse response, @Nonnull Object handler) throws Exception {
// 在请求处理之前执行,返回true表示继续处理请求,返回false表示中断请求
String token = request.getHeader("token");
String timeoutStr = "{\"code\":401,\"msg\":\"登录超时\"}";
String roleStr = "{\"code\":403,\"msg\":\"暂无访问权限\"}";
if ("".equals(token) || null == token) {
logger.error("请输入token");
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
try (PrintWriter out = response.getWriter()) {
out.write(timeoutStr);
}
return false;
}
if (!redisUtil.hasKey(token)) {
logger.error("token失效,请重新登录");
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
try (PrintWriter out = response.getWriter()) {
out.write(timeoutStr);
}
return false;
}
String userId = TokenUtil.JudgementToken(token);
Integer roleId = user.getRoleIdByUserId(Integer.valueOf(userId));
List<String> menuList = user.getMenuIdListByRole(roleId);
String uri = request.getRequestURI();
boolean found = false;
for (String menu : menuList) {
if (uri.contains(menu)) {
found = true;
break;
}
}
if (!found) {
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
try (PrintWriter out = response.getWriter()) {
out.write(roleStr);
}
return false;
}
return true;
}
}
拦截器配置
最后,需要将自定义的拦截器注册到Spring MVC配置中。这可以通过实现WebMvcConfigurer
接口来完成。
@Configuration
public class WebAppConfigurer implements WebMvcConfigurer{
@Autowired
private MyInterceptor myInterceptor;
@Bean
public HttpMessageConverter responseBodyConverter(){
StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
return converter;
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters){
converters.add(responseBodyConverter());
}
@Override
public void addCorsMappings(CorsRegistry registry){
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET","HEAD","POST","PUT","DELETE","OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
@Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(myInterceptor)
.addPathPatterns("/**")// 拦截所有路径
.excludePathPatterns("/login","/getVerifyCode","/logout","/error");// 放行路径
}
}
通过上面的方法,我们实现了角色权限的管理。