有时候我们希望某些方法只允许携带某些权限的用户可以访问,且隔离级别大于角色管理的配置,这时候我们就可以使用到权限注解,但是这套框架都是我们自己编写的,那理所当然权限注解也就我们自己去实现了。
当我们在启动程序的时候输入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,代码如下:
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 {};
}
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;
}
}
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);
}
启动我们的项目,然后使用一个没有系统管理员角色的用户登录系统,然后进入到数据字典的查询模块,我们会看到如下的效果。