大型网站制作需要什么设备,抽奖网站开发,有免费推广平台,学的网络工程基于handleMethod写的一款分级式接口权限检查方案。 权限自动同步机制#xff08;启动更新#xff0c;页面不提供增删改#xff09;#xff1a;
public class AuthorizationMappingGenerateExecutor implements EasyApplicationRunner {Autowiredprivate AuthorizationMap…基于handleMethod写的一款分级式接口权限检查方案。 权限自动同步机制启动更新页面不提供增删改
public class AuthorizationMappingGenerateExecutor implements EasyApplicationRunner {Autowiredprivate AuthorizationMappingMapper authorizationMappingMapper;Autowiredprivate RequestMappingHandlerMapping mapping;Autowiredprivate SupportSecurityProperties securityProperties;// 启动时执行一次随便用用作个排序。没安全问题int i 0;Overridepublic void doBusiness() {MapRequestMappingInfo, HandlerMethod handlerMethodMap mapping.getHandlerMethods();CollectionHandlerMethod handlerMethods handlerMethodMap.values();// 表中已存在的codeListString existsCodes authorizationMappingMapper.selectProperties(Wrappers.lambdaQuery(), AuthorizationMapping::getCode);// 排重setSetString currentExistsCodes new HashSet();// 配置的级别MappingLevel mappingLevel securityProperties.getMappingLevel();// 添加的权限ListAuthorizationMapping insertMappings new ArrayList();// 需要更新的权限ListAuthorizationMapping updateMappings new ArrayList();for (HandlerMethod handlerMethod : handlerMethods) {Class? beanType handlerMethod.getBeanType();String name beanType.getName();// 只取本系统内的接口if (!name.contains(xxxx)) {continue;}AuthorizationMapping moduleMapping buildModuleMapping(handlerMethod);int type chooseType(existsCodes, currentExistsCodes, moduleMapping);if (type 1) {insertMappings.add(moduleMapping);} else if (type 2) {updateMappings.add(moduleMapping);}// 只开启了一级权限检查if (mappingLevel.is(MappingLevel.MODULE)) {continue;}AuthorizationMapping controllerMapping buildControllerMapping(moduleMapping.getCode(), handlerMethod);int controllerType chooseType(existsCodes, currentExistsCodes, controllerMapping);if (controllerType 1) {insertMappings.add(controllerMapping);} else if (controllerType 2) {updateMappings.add(controllerMapping);}// 只开启了二级权限检查if (mappingLevel.is(MappingLevel.CONTROLLER)) {continue;}// 方法级的权限检查AuthorizationMapping methodMapping buildMethodMapping(controllerMapping.getCode(), handlerMethod);int methodType chooseType(existsCodes, currentExistsCodes, methodMapping);if (methodType 1) {insertMappings.add(methodMapping);} else if (methodType 2) {updateMappings.add(methodMapping);}}// 批量插入authorizationMappingMapper.insertSplitBatch(insertMappings, 200);// 配置是否更新一条条更新太慢影响启动速度。if (securityProperties.getEnableMappingUpdate()) {updateMappings.forEach(authorizationMappingMapper::updateById);}// 清掉子级不占表空间。开放的话重启构建即可。code不会变LambdaQueryWrapperAuthorizationMapping wrapper Wrappers.lambdaQuery();if (mappingLevel.is(MappingLevel.MODULE)) {wrapper.in(AuthorizationMapping::getLevel, ZYListUtils.toList(MappingLevel.CONTROLLER.level(), MappingLevel.METHOD.level()));} else if (mappingLevel.is(MappingLevel.CONTROLLER)) {wrapper.eq(AuthorizationMapping::getLevel, MappingLevel.METHOD.level());}authorizationMappingMapper.delete(wrapper);}private int chooseType(ListString existsCodes, SetString currentExistsCodes, AuthorizationMapping methodMapping) {String code methodMapping.getCode();if (currentExistsCodes.contains(code)) {return 0;}// 去重currentExistsCodes.add(methodMapping.getCode());// 更新or插入if (!existsCodes.contains(code)) {return 1;} else {return 2;}}// 构建模块权限private AuthorizationMapping buildModuleMapping(HandlerMethod handlerMethod) {Class? beanType handlerMethod.getBeanType();Package aPackage beanType.getPackage();AuthorizationMapping packageMapping buildBaseMapping(MappingLevel.MODULE);packageMapping.setMapping();packageMapping.setParentCode(ZYTreeUtils.TREE_ROOT_ID);String moduleCode PermissionMappingGenerator.generateModuleKey(handlerMethod);packageMapping.setCode(moduleCode);String packageName aPackage.getName();packageMapping.setFileLocal(packageName);String packageChinaName try2getPackageChinaName(handlerMethod);packageMapping.setName(null ! packageChinaName ? packageChinaName : packageName);return packageMapping;}// 构建controller级权限private AuthorizationMapping buildControllerMapping(String parentCode, HandlerMethod handlerMethod) {AuthorizationMapping packageMapping buildBaseMapping(MappingLevel.CONTROLLER);packageMapping.setMapping();packageMapping.setParentCode(parentCode);String controllerCode PermissionMappingGenerator.generateControllerKey(handlerMethod);packageMapping.setCode(controllerCode);Class? beanType handlerMethod.getBeanType();packageMapping.setFileLocal(beanType.getName());Theme theme beanType.getAnnotation(Theme.class);packageMapping.setName(null ! theme ? theme.value() : beanType.getSimpleName());return packageMapping;}// 构建方法级权限private AuthorizationMapping buildMethodMapping(String parentCode, HandlerMethod handlerMethod) {String methodCode PermissionMappingGenerator.generateMethodKey(handlerMethod);AuthorizationMapping packageMapping buildBaseMapping(MappingLevel.METHOD);packageMapping.setCode(methodCode);packageMapping.setParentCode(parentCode);Class? beanType handlerMethod.getBeanType();Method method handlerMethod.getMethod();packageMapping.setFileLocal(beanType.getName() . method.getName());packageMapping.setMapping(spellMapping(method, beanType));packageMapping.setName(getMappingName(handlerMethod));return packageMapping;}private AuthorizationMapping buildBaseMapping(MappingLevel level) {AuthorizationMapping packageMapping new AuthorizationMapping();packageMapping.setCreateDate(System.currentTimeMillis());packageMapping.setIsMiniAuth(0);packageMapping.setSort(i);packageMapping.setLevel(level.level());packageMapping.setRemarks(level.getMappingName());return packageMapping;}private String getMappingName(HandlerMethod handlerMethod) {SystemLog systemLog handlerMethod.getMethodAnnotation(SystemLog.class);if (null ! systemLog) {return systemLog.value();}return handlerMethod.getMethod().getName();}private String spellMapping(Method method, Class? beanType) {StringBuilder path new StringBuilder();RequestMapping parentRequestMapping beanType.getAnnotation(RequestMapping.class);if (null ! parentRequestMapping) {String[] value parentRequestMapping.value();if (value.length 0) {path.append(value[0]);}}RequestMapping methodRequestMapping method.getAnnotation(RequestMapping.class);GetMapping methodGetRequestMapping method.getAnnotation(GetMapping.class);PostMapping methodPostRequestMapping method.getAnnotation(PostMapping.class);if (null ! methodRequestMapping) {String[] value methodRequestMapping.value();if (value.length 0) {path.append(value[0]);}} else if (null ! methodGetRequestMapping) {String[] value methodGetRequestMapping.value();if (value.length 0) {path.append(value[0]);}} else if (null ! methodPostRequestMapping) {String[] value methodPostRequestMapping.value();if (value.length 0) {path.append(value[0]);}}return path.toString();}private String try2getPackageChinaName(HandlerMethod handlerMethod) {Class? beanType handlerMethod.getBeanType();Package aPackage beanType.getPackage();Theme packageTheme aPackage.getAnnotation(Theme.class);if (null ! packageTheme) {return packageTheme.value();}return null;}
}权限检查拦截器
public class AuthorizationMappingInterceptor implements EasyMvcInterceptor, InitializingBean {private final static SetString NO_NEED_CHECK_CODES new HashSet();private final static SetString CHECK_CODES new HashSet();Autowiredprivate AuthorizationMappingMapper authorizationMappingMapper;Autowiredprivate SupportSecurityProperties securityProperties;Overridepublic boolean doBusiness(HandlerMethod handlerMethod, HttpServletRequest request, HttpServletResponse response) {// 开放接口if (ZYRequestUtils.isDirectApi()) {return true;}// 超管if (UserHelper.isSuperAdmin()) {return true;}// 需要跳过的权限if (isSkipMappingCheck(handlerMethod)) {return true;}// 查询需要的权限MappingLevel mappingLevel securityProperties.getMappingLevel();String permissionCode PermissionMappingGenerator.generateByLevel(handlerMethod, mappingLevel);// 缓存在存在直接通过检查if (NO_NEED_CHECK_CODES.contains(permissionCode)) {return true;}// 该接口没有做权限限制直接放行if (!CHECK_CODES.contains(permissionCode)) {NO_NEED_CHECK_CODES.add(permissionCode);return true;}// 用户权限信息LoginUser loginAreaUser UserHelper.getLoginAreaUser();SetString mappingCodes loginAreaUser.getMappingCodes();if (!hasPermission(permissionCode, mappingCodes)) {throw new PermissionException(您没有访问接口的权限);}return true;}private boolean hasPermission(String permissionCode, SetString mappingCodes) {return null ! mappingCodes mappingCodes.contains(permissionCode);}Overridepublic void afterPropertiesSet() {// 根据权限级别查询需要检查的HandleMethod或controllerMappingLevel mappingLevel securityProperties.getMappingLevel();LambdaQueryWrapperAuthorizationMapping wrapper Wrappers.lambdaQuery();wrapper.eq(AuthorizationMapping::getLevel, mappingLevel.level());wrapper.eq(AuthorizationMapping::getIsMiniAuth, NO);wrapper.select(AuthorizationMapping::getCode);ListString authorizationMappings authorizationMappingMapper.selectProperties(wrapper, AuthorizationMapping::getCode);CHECK_CODES.addAll(authorizationMappings);}private boolean isSkipMappingCheck(HandlerMethod handlerMethod) {Class? beanType handlerMethod.getBeanType();Package aPackage beanType.getPackage();SkipMappingCheck packageSkip aPackage.getAnnotation(SkipMappingCheck.class);if (null ! packageSkip) {return true;}SkipMappingCheck classSkip beanType.getAnnotation(SkipMappingCheck.class);if (null ! classSkip) {return true;}Method method handlerMethod.getMethod();SkipMappingCheck methodSkip method.getAnnotation(SkipMappingCheck.class);return null ! methodSkip;}
}
public enum MappingLevel implements Matcher {MODULE(模块),CONTROLLER(控制类),METHOD(接口方法);private String mappingName;public String level() {return this.name().toLowerCase();}Overridepublic Object statusCode() {return level();}
}code生成器
public class PermissionMappingGenerator {private final static MapString, String PACKAGE_KEY_CACHE new HashMap();private final static MapString, String CONTROLLER_KEY_CACHE new HashMap();private final static MapString, String METHOD_KEY_CACHE new HashMap();public static String generateByLevel(HandlerMethod handlerMethod, MappingLevel mappingLevel) {switch (mappingLevel) {case METHOD:return generateMethodKey(handlerMethod);case CONTROLLER:return generateControllerKey(handlerMethod);case MODULE:return generateModuleKey(handlerMethod);default:throw new LocalException(不能确定的权限级别);}}public static String generateModuleKey(HandlerMethod handlerMethod) {Class? beanType handlerMethod.getBeanType();Package aPackage beanType.getPackage();String packageName aPackage.getName();String cryptPackageCode PACKAGE_KEY_CACHE.get(packageName);if (ZYStrUtils.isNull(cryptPackageCode)) {cryptPackageCode ZYCryptUtils.encryptMD5(packageName).toLowerCase();PACKAGE_KEY_CACHE.put(packageName, cryptPackageCode);}return cryptPackageCode;}public static String generateControllerKey(HandlerMethod handlerMethod) {Class? beanType handlerMethod.getBeanType();String className beanType.getName();String cryptControllerCode CONTROLLER_KEY_CACHE.get(className);if (ZYStrUtils.isNull(cryptControllerCode)) {cryptControllerCode ZYCryptUtils.encryptMD5(className).toLowerCase();CONTROLLER_KEY_CACHE.put(className, cryptControllerCode);}return cryptControllerCode;}public static String generateMethodKey(HandlerMethod handlerMethod) {Class? beanType handlerMethod.getBeanType();Method method handlerMethod.getMethod();ListString keySign new ArrayList();keySign.add(beanType.getSimpleName());keySign.add(method.getName());Parameter[] parameters method.getParameters();for (Parameter parameter : parameters) {keySign.add(parameter.getName());}String key StrUtils.join(keySign, #);String cryptKey METHOD_KEY_CACHE.get(key);if (null cryptKey) {cryptKey CryptUtils.encryptMD5(key).toLowerCase();METHOD_KEY_CACHE.put(key, cryptKey);}return cryptKey;}
}
Target({ElementType.METHOD, ElementType.TYPE, ElementType.PACKAGE})
Retention(RetentionPolicy.RUNTIME)
public interface SkipMappingCheck {
}
与传统的路径匹配接口权限检查相比本方案采用HandleMethod信息与角角直接绑定。多了一个权限颗粒度划分。对减少接品权限数量及减少人工分配量有明显的优势。自动的权限生成工具省去了维护权限编号协删改查的人工操作。减去了大量人工。实际使用中默认使用module级维护量很少。较严情况下使用controller级。严格安全等保要求的情况下。使用mothod级。方案选择很灵活。重启服务即可任意切换。可以使用SkipMappingCheck 注解对整个模块整个controller进行跳过处理。