Lozinn技术客栈-2.权限模块,控制到按钮级别

2.权限模块

原理:自定义一个权限注解接口,每个对外提供的请求接口配置好权限注解及权限代码,拦截器配置好拦截请求后,会获取每个接口方法上的权限注解的代码,在自定义方法进行相对应的权限判断
如:先从redis中查询用户的角色,判断对应角色是否拥有这个代码权限,数据库需要用户表、角色表、页面权限表、关系关联表

2.1在每个需要权限控制的接口上添加自定义注解,配置权限代码

图片.png

2.2自定义权限注解

package com.lozinn.system.annotation;

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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionCode {
    //页面代码
    long pageCode() default 0;
    //页面授权代码
    long actionCode() default 0;
}

2.3拦截类配置

package com.lozinn.common.config;

import com.lozinn.common.interceptor.AuthenticationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 拦截配置类
 */
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Bean
    AuthenticationInterceptor AuthenticationInterceptor(){
        return new AuthenticationInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry){
        //addPathPatterns设置拦截/**所有请求,同时excludePathPatterns排除指定
        registry.addInterceptor(AuthenticationInterceptor()).addPathPatterns("/**")
                .excludePathPatterns("/error")
                //.excludePathPatterns("/user/addUser")
                .excludePathPatterns("/user/userLogin")
                .excludePathPatterns("/swagger-ui.html");
    }
}

2.4配置身份验证的拦截器

package com.lozinn.common.interceptor;

import com.alibaba.druid.util.StringUtils;
import com.lozinn.common.util.JWTUtils;
import com.lozinn.system.annotation.PermissionCode;
import com.lozinn.system.exception.MyException;
import com.lozinn.system.exception.TokenException;
import com.lozinn.system.myenum.ExceptionCodeEnum;
import com.lozinn.system.service.PermissionService;
import com.lozinn.system.util.UserThreadLocal;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

/**
 * 身份验证拦截器
 */
@Slf4j
public class AuthenticationInterceptor implements HandlerInterceptor {
    @Autowired
    PermissionService permissionService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //权限拦截验证
        String url = request.getRequestURI();
        String token = request.getHeader("Authorization");
        if(StringUtils.isEmpty(token)){
            throw new TokenException();
        }
        String userId = null;
        try{
            //校验token并获取userId
            userId = JWTUtils.getUserIdFromToken(token);
        }catch (Exception e){
            if(e instanceof ExpiredJwtException){
                log.info("token ExpiredJwtException:"+ExceptionCodeEnum.TOKEN_EXPIRED_ERROR.getMsg());
                throw new MyException(ExceptionCodeEnum.TOKEN_EXPIRED_ERROR);
            }else if(e instanceof SignatureException){
                log.info("token SignatureException:"+ExceptionCodeEnum.TOKEN_CHECK_FAIL.getMsg());
                throw new MyException(ExceptionCodeEnum.TOKEN_CHECK_FAIL);
            }else if(e instanceof MalformedJwtException){
                log.info("token MalformedJwtException:"+ExceptionCodeEnum.MALFORMEDJWT_ERROR.getMsg());
                throw new MyException(ExceptionCodeEnum.MALFORMEDJWT_ERROR);
            }
        }
        //线程保存userId,afterCompletion注销userId,使userId只在请求过程中可用
        UserThreadLocal.setUserId(Long.parseLong(userId));

        //校验用户权限
        if(handler instanceof HandlerMethod){
            HandlerMethod hm = (HandlerMethod) handler;
            Class clazz = hm.getBeanType();
            Method m = hm.getMethod();
            if(m != null && m.isAnnotationPresent(PermissionCode.class)){
                PermissionCode permissionCode = m.getAnnotation(PermissionCode.class);
                log.info("------>userId:"+userId+",access Method name-->:"+m.getName()+",pageCode:"+permissionCode.pageCode()+",actionCode:"+permissionCode.actionCode());
//这里是具体的权限业务控制,可自行定义,一般是根据userId获取角色并判断是否拥有pageCode和actionCode
                permissionService.getUserPermission(userId,permissionCode.pageCode(),permissionCode.actionCode());
            }
        }
        return true;
    }
    @Override
    public void  postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }
    @Override
    public void  afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        UserThreadLocal.setUserId(null);
    }
}

你可能感兴趣的:(Lozinn技术客栈-2.权限模块,控制到按钮级别)