您的当前位置:首页正文

spring boot+iview 前后端分离架构之权限注解的实现(三十五)

2024-11-29 来源:个人技术集锦

公众号

权限注解

有时候我们希望某些方法只允许携带某些权限的用户可以访问,且隔离级别大于角色管理的配置,这时候我们就可以使用到权限注解,但是这套框架都是我们自己编写的,那理所当然权限注解也就我们自己去实现了。

BUG修复

当我们在启动程序的时候输入http://127.0.0.1:8080/的时候并没有任何的页面响应,这种结果很明显不是我们想要的,出现这种结果的原因是没有在router里面配置默认的访问页,因此我们在router里面增加以下的配置即可修复该问题。

{
    path: '/',
    name: 'login_default',
    meta: {
      icon: 'ios-settings',
      hideInMenu: true,
      title: '登陆页',
      requireAuth: false //表示当前响应的请求是否需要进行登录拦截验证【true:需要;false:不需要】
    },
    component: resolve => {
      require(['../view/login/login.vue'], resolve);
    }
  }

权限注解的实现

首先在core包底下创建一个annotation包,然后在annotation包里实现我们的AuthController注解,以及该注解的拦截AuthControllerInterceptor,代码如下:

AuthController注解的实现

package com.github.bg.admin.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author linzf
 * @since 2019-06-10
 * 类描述:controller方法的鉴权的注解
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthController {

    /**
     * 允许响应的权限的集合
     * @return
     */
    String[] authorities() default {};


}

AuthControllerInterceptor注解权限拦截的实现

package com.github.bg.admin.core.annotation.filter;


import com.github.bg.admin.core.annotation.AuthController;
import com.github.bg.admin.core.auth.ReleaseUrl;
import com.github.bg.admin.core.constant.SystemStaticConst;
import com.github.bg.admin.core.util.RedisCache;
import com.github.bg.admin.core.util.StringUtils;
import com.github.bg.admin.core.util.WriteUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * @author linzf
 * @since 2019/6/10
 * 类描述:角色鉴权拦截器的实现
 */
public class AuthControllerInterceptor implements HandlerInterceptor {

    /**
     * 获取放行的权限的接口
     */
    @Autowired
    private ReleaseUrl releaseUrl;

    /**
     * redis工具类
     */
    @Autowired
    private RedisCache redisCache;

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) {
        if (SystemStaticConst.ACTION_TYPE_OPTIONS.equals(httpServletRequest.getMethod())) {
            return true;
        }
        String actionUrl = httpServletRequest.getServletPath();
        // 判断当前的响应地址是否可以放行
        String releasePath = releaseUrl.getReleaseUrl();
        if (releasePath.indexOf(actionUrl) == -1) {
            // 将handler强转为HandlerMethod, 前面已经证实这个handler就是HandlerMethod
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            // 从方法处理器中获取出要调用的方法
            Method method = handlerMethod.getMethod();
            // 获取出方法上的AuthController注解
            AuthController authController = method.getAnnotation(AuthController.class);
            if (authController == null) {
                // 如果注解为null, 说明不需要拦截, 直接放过
                return true;
            }
            if (authController.authorities().length > 0) {
                // 如果权限配置不为空, 则取出配置值
                String[] authorities = authController.authorities();
                String token = httpServletRequest.getHeader("x-access-token");
                if (token == null || "".equals(token) || "null".equals(token)) {
                    WriteUtil.write(httpServletResponse, SystemStaticConst.NOT_LOGIN, "用户未登录");
                    return false;
                }
                String[] userRoles = StringUtils.getObjStr(redisCache.getString(token + "_USER_ROLE")).split(":");
                if (userRoles.length == 0) {
                    WriteUtil.write(httpServletResponse, SystemStaticConst.AUTH_FAIL, "用户无权限访问");
                    return false;
                }
                // 判断当前的用户的角色是否有当前节点的角色权限,若有则放行,若无则不放行
                for (String auth : authorities) {
                    for (String userRole : userRoles) {
                        if(auth.equals(userRole)){
                            return true;
                        }
                    }
                }
                WriteUtil.write(httpServletResponse, SystemStaticConst.AUTH_FAIL, "用户无权限访问");
                return false;
            }
        }
        return true;
    }

}

InterceptorConfig改造

package com.github.bg.admin.core.config;

import com.github.bg.admin.core.annotation.filter.AuthControllerInterceptor;
import com.github.bg.admin.core.filter.AuthInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author linzf
 * @since 2019-06-04
 * 类描述:设置拦截器
 */
@Component
public class InterceptorConfig implements WebMvcConfigurer {

    /**
     * 初始化鉴权拦截器
     */
    private AuthInterceptor authInterceptor = new AuthInterceptor();

    /**
     * 初始化角色拦截器
     */
    private AuthControllerInterceptor authControllerInterceptor = new AuthControllerInterceptor();

    /**
     * 注入权限拦截器bean
     */
    @Bean
    AuthInterceptor authInterceptor(){
        return  authInterceptor;
    }

    /**
     * 注入权限注解拦截器bean
     */
    @Bean
    AuthControllerInterceptor authControllerInterceptor() {
        return authControllerInterceptor;
    }


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 先加的拦截器先执行
        registry.addInterceptor(authInterceptor()).addPathPatterns("/**");
        registry.addInterceptor(authControllerInterceptor()).addPathPatterns("/**");
    }


}

权限注解的使用

那么我们现在假设我们的数据字典的列表查询方法只能是系统管理员的角色可以使用,其他角色即使分配了该权限也不允许使用字典查询,那么我们只需要在字典查询的方法上添加以下的注解【@AuthController(authorities={“system-admin”})】,改注解的authorities支持多权限因为他接收的是一个数组。

/**
     * 功能描述:获取数据字典列表
     *
     * @param search       模糊匹配数据字典的dictType、dictText、dictValue、dictCode 允许为空
     * @param dictCode     模糊查询dictCode
     * @param pageSize     每页显示的记录的条数
     * @param current      当前访问第几页
     * @param orderKey     排序字段
     * @param orderByValue 排序方式,降序还是升序
     * @return 返回查询结果
     */
    @ApiOperation(value = "获取数据字典列表")
    @PostMapping("queryDictList")
    @AuthController(authorities={"system-admin"})
    public ReturnInfo queryDictList(@RequestParam(name = "search", required = false) String search,
                                    @RequestParam(name = "dictCode", required = false) String dictCode,
                                    @RequestParam(name = "pageSize") int pageSize,
                                    @RequestParam(name = "current") int current,
                                    @RequestParam(name = "orderKey", required = false) String orderKey,
                                    @RequestParam(name = "orderByValue", required = false) String orderByValue) {
        return dictService.queryDictList(search, dictCode, pageSize, current, orderKey, orderByValue);
    }

验证我们的权限注解

启动我们的项目,然后使用一个没有系统管理员角色的用户登录系统,然后进入到数据字典的查询模块,我们会看到如下的效果。

显示全文