当前位置:首页 > 技术 > 正文内容

基于Spring Boot的权限控制系统实现

访客 技术 2026年8月2日 2

在企业级应用开发中,权限管理是保障系统安全的核心环节。不同角色的用户需要访问不同的功能模块,例如财务部门只能访问财务相关功能,而销售部门则只能访问销售模块。本文将介绍如何通过Spring Boot的拦截器机制实现灵活的权限控制系统。

系统设计采用用户-角色-权限的三层结构,每个用户拥有多个角色,每个角色又关联多个具体权限。

数据库表结构

数据库表结构

拦截器配置

WebMvcConfig

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

    @Autowired
    private AccessControlInterceptor accessControlInterceptor;

    @Bean
    public CustomInterceptor customInterceptor() {
        return new CustomInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(accessControlInterceptor);
        registry.addInterceptor(customInterceptor())
                .addPathPatterns("/**")
                .addPathPatterns("/admin/**")
                .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/config/**");
        super.addInterceptors(registry);
    }

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    @Bean
    public ErrorProperties errorProperties() {
        final ErrorProperties properties = new ErrorProperties();
        properties.setIncludeStacktrace(IncludeStacktrace.ALWAYS);
        return properties;
    }

    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters() {
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        fastConverter.setFastJsonConfig(fastJsonConfig);
        return new HttpMessageConverters(fastConverter);
    }

    @Bean(name = "multipartResolver")
    public MultipartResolver multipartResolver() {
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        resolver.setDefaultEncoding("UTF-8");
        resolver.setResolveLazily(true);
        resolver.setMaxInMemorySize(40960);
        resolver.setMaxUploadSize(5 * 1024 * 1024);
        return resolver;
    }
}

CustomInterceptor

@Component
public class CustomInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(CustomInterceptor.class);

    @Autowired
    AccessControlService accessControlService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        accessControlService.test();
        System.out.println(accessControlService.test());
        System.out.println(request);
        System.out.println(response);
        System.out.println(handler);

        if (accessControlService.verifyAccess(request, response, handler)) {
            return true;
        }

        response.sendError(HttpStatus.FORBIDDEN.value(), "无访问权限");
        
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        String methodName = method.getName();
        logger.info("拦截到方法:{},执行前验证", methodName);

        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.info("方法执行完成,视图渲染前");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.info("请求处理完成,视图已渲染");
    }
}

权限常量定义

AccessPermissionConstants

public class AccessPermissionConstants {
    // 商品管理权限
    public static final String PRODUCT_LIST = "product_list_query";
    public static final String PRODUCT_DELETE = "product_delete";
    public static final String PRODUCT_CREATE = "product_create";
    public static final String PRODUCT_MODIFY = "product_modify";

    // 角色管理权限
    public static final String ROLE_LIST = "role_list_query";
    public static final String ROLE_CREATE = "role_create";
    public static final String ROLE_MODIFY = "role_modify";
    public static final String ROLE_DELETE = "role_delete";

    // 商品类目权限
    public static final String CATEGORY_LIST = "category_list_query";
    public static final String CATEGORY_CREATE = "category_create";
    public static final String CATEGORY_MODIFY = "category_modify";
    public static final String CATEGORY_DELETE = "category_delete";

    // 会员管理权限
    public static final String MEMBER_LIST = "member_list_query";
    public static final String MEMBER_DELETE = "member_delete";
    public static final String MEMBER_CREATE = "member_create";
    public static final String MEMBER_MODIFY = "member_modify";

    // 资产管理权限
    public static final String PROPERTY_LIST = "property_list_query";
    public static final String PROPERTY_DETAIL = "property_detail_view";
    public static final String PROPERTY_WITHDRAW = "property_withdraw";

    // 活动管理权限
    public static final String ACTIVITY_LIST = "activity_list_query";
    public static final String ACTIVITY_DETAIL = "activity_detail_view";
    public static final String ACTIVITY_ACTIVATE = "activity_activate";
    public static final String ACTIVITY_CREATE = "activity_create";
    public static final String ACTIVITY_MODIFY = "activity_modify";
    public static final String ACTIVITY_DELETE = "activity_delete";

    // 管理员权限
    public static final String ADMIN_LIST = "admin_list_query";
    public static final String ADMIN_MODIFY = "admin_modify";
}

权限注解定义

AccessPermission

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface AccessPermission {
    String value();
}

权限验证服务实现

AccessControlServiceImpl

@Service
public class AccessControlServiceImpl implements AccessControlService {

    @Autowired
    private UserRoleMapper userRoleMapper;
    
    @Autowired
    private RolePermissionMapper rolePermissionMapper;
    
    @Autowired
    private PermissionMapper permissionMapper;

    @Override
    public boolean verifyAccess(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("进入权限验证服务");
        
        String userId = extractUserIdFromRequest(request);
        if (userId == null) {
            return false;
        }
        
        List<UserRole> userRoles = getUserRoles(userId);
        if (userRoles.isEmpty()) {
            return false;
        }
        
        Integer roleId = userRoles.get(0).getRoleId();
        List<RolePermission> rolePermissions = getRolePermissions(roleId);
        
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            
            // 获取方法上的注解
            AccessPermission accessPermission = handlerMethod.getMethod().getAnnotation(AccessPermission.class);
            
            // 如果方法上的注解为空,则获取类的注解
            if (accessPermission == null) {
                accessPermission = handlerMethod.getMethod().getDeclaringClass().getAnnotation(AccessPermission.class);
            }
            
            // 如果没有权限注解,则允许访问
            if (accessPermission == null) {
                return true;
            }
            
            // 如果标记了注解,则验证权限
            if (accessPermission != null && StringUtils.isNotBlank(accessPermission.value())) {
                if (rolePermissions.isEmpty()) {
                    return false;
                }
                
                for (RolePermission rolePermission : rolePermissions) {
                    Integer permissionId = rolePermission.getPermissionId();
                    Permission permission = permissionMapper.selectByPrimaryKey(permissionId);
                    if (accessPermission.value().equals(permission.getAccessCode())) {
                        return true;
                    }
                }
                return false;
            }
        }
        
        return true;
    }
    
    private String extractUserIdFromRequest(HttpServletRequest request) {
        String userId = "123";
        Cookie[] cookies = request.getCookies();
        
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("autologin".equals(cookie.getName())) {
                    userId = cookie.getValue();
                    break;
                }
            }
        }
        
        return userId;
    }
    
    private List<UserRole> getUserRoles(String userId) {
        Example example = new Example(UserRole.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("userId", userId);
        return userRoleMapper.selectByExample(example);
    }
    
    private List<RolePermission> getRolePermissions(Integer roleId) {
        Example example = new Example(RolePermission.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("roleId", roleId);
        return rolePermissionMapper.selectByExample(example);
    }

    @Override
    public int test() {
        System.out.println("测试方法调用");
        return 0;
    }
}

用户认证

登录时将用户ID存储在Cookie中,实现会话跟踪。后续可扩展为JWT Token支持分布式系统。

Cookie cookie = new Cookie("autologin", authKey);
cookie.setPath("/");
response.addCookie(cookie);

使用方法 在需要权限控制的接口或方法上添加注解:

@RestController
@RequestMapping("/admin/product")
public class ProductController {
    
    @GetMapping("/list")
    @AccessPermission(AccessPermissionConstants.PRODUCT_LIST)
    public List<Product> getProductList() {
        // 商品列表查询逻辑
        return productService.getAllProducts();
    }
    
    @PostMapping("/create")
    @AccessPermission(AccessPermissionConstants.PRODUCT_CREATE)
    public Product createProduct(@RequestBody Product product) {
        // 创建商品逻辑
        return productService.addProduct(product);
    }
}

通过以上实现,系统可以根据用户角色动态控制接口访问权限,确保不同用户只能访问其权限范围内的功能模块。

标签: Spring Boot

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。