功能需求
遇到一个问题,要实现权限管理,也就是有些按钮点击时要提示,没有权限,有很多接口,如果要是按照老的方式,就是每个方法都手写权限判断.十分浪费时间
问题的重要点
- 重复的工作,如何解决
- 项目并没有引入shiro之类的模块而且session是保存在redis中的,所以分布式的环境也可使用session,如何从session中获取用户信息
话不多少,直接说怎么做
- 采用aop实现重复的权限判断
- 根据RequestContextHolder这个类可以获取session
Permission注解
import java.lang.annotation.*;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
/**
* 此处在使用时,可以在方法上面加注解
* example: @Permission({"/admin/hasPermission","/admin/isAlive"})
* */
public @interface Permission {
String[] value() default {};
}
复制代码
PermissionAop
import com.seniortech.test.annotation.Permission;
import com.seniortech.test.entity.Admin;
import com.seniortech.test.response.LayData;
import com.seniortech.test.service.PermissionService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.aspectj.lang.reflect.MethodSignature;
import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.Objects;
/**
* @author husky
* @date 2019/6/24 17:46
*/
@Aspect
@Configuration
public class PermissionAop {
@Resource
private PermissionService permissionService;
// 定义切点Pointcut
@Pointcut(value="@annotation(com.seniortech.test.annotation.Permission)")
public void excudeService(){
}
@Around("excudeService()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
HttpSession session = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest().getSession();
Admin admin =(Admin) session.getAttribute("admin");//上面两行代码可以获取到request,即可以获取session
if(!Objects.isNull(admin)){
System.out.println(admin);
MethodSignature ms = (MethodSignature) proceedingJoinPoint.getSignature();
Method method = ms.getMethod();
Permission permission = ((Method) method).getAnnotation(Permission.class);
String[] permissions = permission.value();//此处可以获取@Permission中的注解,字符串数组
//当然要对这个permissions这个判断是否长度为0,本代码中未判断是不严谨的
if(!permissionService.hasPermission(admin.getId(),permissions)){
return LayData.builder().code(-1).msg("没有权限").build();
}
//此处的LayData是response的统一格式
}
Object result = proceedingJoinPoint.proceed();
return result;
}
}
复制代码
前端ajax处的封装代码
/**
* ajax封装
* url 发送请求的地址
* data 发送到服务器的数据,数组存储,如: {"date":new Date().getTime(),"state":1}
* successfn 成功回调函数
* errorfn 失败回调函数
* */
jQuery.postAjax = function (url,data,successfn,errorfn) {
data = (data === null || data === ""
|| typeof (data) === "undefined")
?{"date":new Date().getTime()}:data;
var loadObj = layer.load(2);
$.ajax({
type: "post",
data: data,
url: url,
success: function (d,textStatus,jqXHR) {
layer.close(loadObj);
if(d.code === -100){//登录状态已失效
layer.confirm("登录已失效,请重新登录",
{icon:2,title: '提示',btn: ['确定'],
closeBtn:0},function (index) {
window.location.href = "/login.html";
})
return;
}
if(d.code === -1) {//无权操作或权限被禁
console.log("没有权限");
layer.msg(d.msg,{icon:0});
return;
}
successfn(d);
},
error:function (e) {
layer.close(loadObj);
if(errorfn !== undefined){
errorfn(e);
}
}
})
}
复制代码
后端调用代码
@Permission("/admin/disable")
@RequestMapping("/disable")
@ResponseBody
public Object administratorDisable(Integer userId){
Integer returnCode = adminService.setStatus(Admin.builder().id(userId.longValue()).status(false).build());
if(returnCode == 0){
return LayData.builder().code(400).build();
}else{
return LayData.builder().code(200).build();
}
}
复制代码
我会更加赞同一些观点,偷懒也是人类进步的阶梯.
在我发现要做重复的事情的时候,第一个想到的事情,应该是十分有方法简化它
此处,要感谢guns开源框架,给我的灵感,使用注解实现aop