公司的系统比较老了,再加上成本限制,信息安全方面做的不够好,菜单的权限分配是靠判断是否在首页展示给用户来决定的,如果有人能够拿到未被展示的菜单中执行相关业务逻辑的url(比如修改密码的url:/user/changePassword),即使没有权限也能进入。
由于数据库中只存储了用户与角色的关联、角色与菜单项的关联信息,并没有存储用户或角色与具体业务逻辑url之间的关联信息,因此我想到了利用拦截器来实现鉴权功能,虽然略微有些麻烦,但至少应该比将业务逻辑url也录入进去再重新给用户分配权限来的容易。
各位看官如果有什么更好的办法,欢迎分享!
- 首先是自定义注解:
package cn.bzdj.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
/**
- 自定义注解,用于鉴权
- @author bzdj
- */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuthUrl {
//参数填写父级url,拥有任意父级url的访问权限,即拥有被注解的controller的访问权限
String[] urls();
}
- 然后是拦截器:
package cn.bzdj.interceptor;
import java.math.BigDecimal;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import cn.bzdj.annotation.AuthUrl;
/**
* 利用注解AuthUrl来鉴权
* @author bzdj
* */
public class PrevilegeInterceptor extends HandlerInterceptorAdapter {
@Autowired
PrevilegeMapper pm; //这里换成自己鉴权用到的mapper
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String[] urls=null;
if(handler instanceof HandlerMethod) {
HandlerMethod h = (HandlerMethod)handler;
if(h.getMethodAnnotation(AuthUrl.class)==null) //无AuthUrl注解则放行
return true;
urls=h.getMethodAnnotation(AuthUrl.class).urls();
if(urls==null||urls.length==0) //空AuthUrl注解则放行
return true;
//这里填写自己的判断当前用户是否拥有权限的代码,如果有则return true。
}else{
return true; //放行静态资源(spring mvc 3.2及以上版本可在xml或配置类中配置)
}
response.sendRedirect(request.getContextPath()+"/index.jsp"); //无权限则重定向到首页
return false;
}
}
- 之后是配置:
<mvc:interceptors>
<bean class="cn.bzdj.interceptor.PrevilegeInterceptor" />
</mvc:interceptors>
如果spring mvc版本在3.2及以上,可在此处配置放行静态资源。其他配置差别自行查看相关文档或百度。
- 最后是使用:
还拿上面修改密码为例
@PostMapping("/changePassword")
@ResponseBody
@AuthUrl(urls={"/a","/b","/c"}) //引号中填写需要拥有哪些菜单的访问权限才能使用此url,有多少个就填多少个,不需要鉴权的不加此注解
public Json changePassword(User user){
//相关业务逻辑
}
- 总结:
由于数据库仅存储了菜单权限,子级url是否有权限只能通过这些菜单的url进行判断,因此想到了拦截器+自定义注解的方法。之所以不用AOP,原因是需要拿到session中存储的相关数据,用拦截器更加方便。如果各位看官觉得代码还可以再简化,或者有更好的解决方案,欢迎留言讨论!