定义redis缓存权限对象userSession
package com.yasinyt.admin.web.vo;
import java.util.List;
import com.yasinyt.admin.entity.Emplyee;
import com.yasinyt.admin.entity.Permission;
import com.yasinyt.admin.entity.Role;
import com.yasinyt.admin.entity.User;
import lombok.Data;
import lombok.ToString;
/**
* @author TangLingYun
* @describe 分布式Session对象--用于存储Redis
*/
@Data
@ToString
public class UserSessionVO {
private User user;
private Emplyee emlpyee;
private List<Role> roles;
private List<List<Permission>> permissions;
}
定义权限注解放置某个方法的头上(表示该方法需要权限才能访问):
package com.yasinyt.admin.base.annotation;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* @author TangLingYun
* @describe 访问接口权限验证(特定的用戶不需要权限直接访问)
*/
@Target({ METHOD })
@Retention(RUNTIME)
public @interface RequiresPermission {
/** 需要的权限 */
String[] permisson() default {};
/** 是否指定特定的用戶 默認false */
boolean isSpecific() default false;
/** 特定的用戶 默认admin用户 */
String[] specificUsers() default { "admin" };
}
定义切面编程AOP类进行权限验证(通过redis缓存获取权限对象userSession)
package com.yasinyt.admin.base.aspect;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint;
import org.springframework.aop.framework.ReflectiveMethodInvocation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.yasinyt.admin.base.annotation.RequiresPermission;
import com.yasinyt.admin.base.constant.CookieConstant;
import com.yasinyt.admin.base.exception.AuthorizeException;
import com.yasinyt.admin.base.exception.OpsException;
import com.yasinyt.admin.entity.Permission;
import com.yasinyt.admin.entity.User;
import com.yasinyt.admin.enums.ActiveStatusEnum;
import com.yasinyt.admin.enums.ResultEnum;
import com.yasinyt.admin.util.ArrayUtil;
import com.yasinyt.admin.util.CookieUtil;
import com.yasinyt.admin.util.redis.RedisClient;
import com.yasinyt.admin.util.redis.UserSessionKey;
import com.yasinyt.admin.web.vo.UserSessionVO;
/**
* @author TangLingYun
* @describe 权限验证AOP
*/
@Aspect
@Component
public class PermissionAspect {
@Autowired
private RedisClient redisClient;
@Pointcut("@annotation(com.yasinyt.admin.base.annotation.RequiresPermission)")
public void verify() {
}
@Before("verify()")
public void doVerify(JoinPoint point) {
RequiresPermission requiresPermission = getRequiresPermission(point);
if(requiresPermission==null) return;
String[] permisson = requiresPermission.permisson();
UserSessionVO userSession = getUserSession();
if(userSession == null) throw new AuthorizeException();
User user = userSession.getUser();
if(requiresPermission.isSpecific() && Arrays.asList(requiresPermission.specificUsers()).contains("admin")) return;
if(requiresPermission.isSpecific() && Arrays.asList(requiresPermission.specificUsers()).contains(user.getUserName())) return;
List<List<Permission>> permissions = userSession.getPermissions();
String[] userPermissions = new String[]{};
for (int i = 0; i < permissions.size(); i++) {
List<Permission> list = permissions.get(i);
String[] userpermission = list.stream().filter(e -> ActiveStatusEnum.ACTIVE.getCode().equals(e.getStatus())).map(Permission::getPermission).collect(Collectors.toList()).toArray(new String[0]);
userPermissions = ArrayUtils.addAll(userPermissions,userpermission);
}
String[] intersect = ArrayUtil.intersect(userPermissions, permisson);
if(intersect.length != permisson.length) throw new OpsException(ResultEnum.NOT_AUTHORIZATION);
}
/**获取需要查询的权限*/
private RequiresPermission getRequiresPermission(JoinPoint point) {
MethodInvocationProceedingJoinPoint methodPoint = (MethodInvocationProceedingJoinPoint) point;
try {
Field proxy = methodPoint.getClass().getDeclaredField("methodInvocation");
proxy.setAccessible(true);
ReflectiveMethodInvocation j = (ReflectiveMethodInvocation) proxy.get(methodPoint);
Method method = j.getMethod();
return method.getAnnotation(RequiresPermission.class);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**获取当前用户的权限session*/
private UserSessionVO getUserSession(){
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
//查询Cookie
Cookie cookie = CookieUtil.getCookie(request, CookieConstant.TOKEN_KEY);
if(cookie==null){
throw new AuthorizeException();
}
UserSessionVO userSessionVO = redisClient.get(UserSessionKey.generateKeyByToken,cookie.getValue(), UserSessionVO.class);
return userSessionVO;
}
}
注解使用(对控制器的权限控制 注意方法上的权限"RequiresPermission"注解):
@GetMapping("findOne")
@RequiresPermission(permisson={"user:findOne"})
public @ResponseBody User findOne(){
System.err.println("findOne");
return null;
}
@GetMapping("userDel")
@RequiresPermission(isSpecific=true,specificUsers={"tanglingyun"})
public @ResponseBody User userDel(){
System.err.println("userDel");
return null;
}
本人才疏学浅,shiro看不懂。故自己写了个简单权限管理类。
具体项目GitHub地址:
github.com/clockworm/ops