仿照shiro实现前后分离项目权限认证

第一部分:访问控制
目的:防止非本系统用户通过http请求操作用户数据
方法
1 当用户执行登录操作的时候,由前端生成token传到后台,后台将token以及该token的过期的时间存储在数据库
2 往后所有的api请求头内必须携带该token,否则该请求无效。如果请求中携带token则前去数据库检索该token的有效性及是否超时
实现

@Component
//拦截所有路径
@WebFilter(urlPatterns = { "/**" }, filterName = "tokenAuthorFilter")
public class ConfigurationFilter implements Filter{
    @Autowired
    shiroService shiroService;
    //定义不需要拦截的url
    private static final Set<String> ALLOWED_PATHS = Collections.unmodifiableSet(new HashSet<>(
            Arrays.asList(
                    "webjars",
                    "druid", 
                    "swagger",
                    "v2",
                    "swagger-ui.html", 
                    "swagger-resources",
                    "configuration",
                    "images"
                    )
            )
            );

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
         HttpServletResponse responses = (HttpServletResponse) response;
         HttpServletRequest requestes = (HttpServletRequest) request;
        // 允许哪些Origin发起跨域请求,nginx下正常
            // response.setHeader( "Access-Control-Allow-Origin", config.getInitParameter( "AccessControlAllowOrigin" ) );
            responses.setHeader( "Access-Control-Allow-Origin", "*" );
            // 允许请求的方法
            responses.setHeader( "Access-Control-Allow-Methods", "POST,GET,OPTIONS,DELETE,PUT" );
            // 多少秒内,不需要再发送预检验请求,可以缓存该结果
            responses.setHeader( "Access-Control-Max-Age", "3600" );
            // 表明它允许跨域请求包含xxx头
            responses.setHeader( "Access-Control-Allow-Headers", "content-type,token" );
            //是否允许浏览器携带用户身份信息(cookie)
            if (requestes.getMethod().equals( "OPTIONS" )) {
                responses.setStatus( 200 );
                return;
            }
            //将不需要拦截的url过滤
            String path = requestes.getRequestURI().substring(requestes.getContextPath().length()).replaceAll("[/]+$", "");
            String paths[] =path.split("/");
            boolean allowedPath = ALLOWED_PATHS.contains(paths[1]);
            if (allowedPath) {
                chain.doFilter(requestes, responses);
            }
            //获取token
            String token=requestes.getHeader("Token");
            //获取该token的用户信息
            sysUserInfo  uInfo= shiroService.queryByToken(token);
            if(uInfo!=null){
                chain.doFilter(requestes, responses);//到下一个链
            }else{
                responses.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                return;
            }
    }
    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub

    }
}

权限控制
思路:仿照shior,给每个用户一个角色,每个角色拥有不同的权限,权限包括不同页面的查看以及不同表的增删改查
步骤: 1建表:分别建立角色表 用户表 页面表 角色与用户对应表
这里写图片描述
这里写图片描述
这里写图片描述

这里写图片描述

如上图所示,有一个用户名为123的用户角色id为1对应角色表里的角色是超级管理员,在角色与用户对应表中角色与用户对应表角色id**1对应的超级管理员拥有页面表中id为12,13**的操作权,在页面表中id 12 13分别对应的是列表页面的新增和查看
2新建注解用于方法中的权限控制

@Retention(RetentionPolicy.RUNTIME) // 表示注解在运行时依然存在
@Target(ElementType.METHOD)  
@Documented
public @interface permission {
    public   String perm() default "";
}

3 在涉及到权限访问的方法上加上权限注解,我们在第一步中的列表查看接口上加上访问权限注解

    @permission(perm = "meau/list")
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    @ApiOperation("获取菜单列表")
    public Map<String,Object> meauList(){
     return meauService.getList();
}
    }

4 核心自定义拦截器拦截有第三步定义的权限注解的方法,然后从请求头中获取token,通过token获取用户信息及该用户拥有的权限集合,如果不包括注解中的权限值则判断该用户没有对方法的访问权

@Component
public class MyInterceptor extends HandlerInterceptorAdapter{

     @Autowired
     private tokenDao tokenDao;

    //在请求处理之前进行调用(Controller方法调用之前
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {

        //如果不是映射到方法直接通过
        if (!(o instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) o;
        Method method = handlerMethod.getMethod();
        if (method.getAnnotation(permission.class) != null) {
            //获取拥有权限注解的方法中的权限值
            permission  permissionAnnotation=method.getAnnotation(permission.class);
            String permStr = permissionAnnotation.perm();
            //获取本次请求中所携带的token信息所属用户的权限列表
             //获取token
            String token=httpServletRequest.getHeader("Token");
            //获取该token的用户信息的权限列表
            List<String> list= tokenDao.queryMeauByToken(token);
            //如果该用户所属权限列表包含该权限值则正常请求    
            if(list.contains(permStr)){
                     return true;
                 }else{
                     httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                     return false;
                 }

        }else{
            return true;
        }
    }

结果测试
从第一步的表中可知用户123的token值为99999999999999999999999999999999
当我们token带上99999999999999999999999999999999请求时
这里写图片描述
当token值不存在时访问
这里写图片描述
当用户123去除该方法的访问权限时访问
这里写图片描述
这里写图片描述

版权声明:本文为weixin_39168678原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39168678/article/details/81702694