shiro jwt springboot

有没有大1佬能教一下用springboot和vue 写权限管理 自己整合了shiro jwt 就不会了 希望能找个人教一下 一对一 自己实在写不出来有偿

想自己写就好好找找案例,跟着写,b站视频也有很多。不想写github也有很多开源的项目

卡在什么地方

总体设计:
通过数据库存储角色、用户、资源信息;
后端通过springboot拦截器对api权限进行控制;
后端提供接口返回用户可访问的模块及组件信息;
前端通过用户可访问模块及组件信息动态加载侧边栏和页面中组件;
权限相关数据库设计:
数据库表还是经典的三张表:角色表(role),用户表(user),资源表(resources)。
role表:默认所有人都有普通用户的权限

img


user表:普通用户不需要专门授权,一个人可以对应多个角色:

img


resources表:存储所有资源
资源表可以理解为树形结构,所有最顶级的组件的parent_id为0;
若要后端对权限进行控制,则需要将uri录入,否则默认不拦截;
若要增加新的权限类型,则资源表也需要增加一个对应的字段控制每个资源的权限。

img

create table role (
  id           int auto_increment  comment '主键id'  primary key,
  role_name    varchar(100)  not null  comment '角色名称',
  role_desc    varchar(200)  default null  comment '角色描述'
) comment '角色管理表'  charset = utf8mb4;

create table user (
  id         bigint auto_increment  comment '主键id'  primary key,
  name       varchar(100)  not null  comment '姓名',
  role_id    int(5)  not null  comment '角色ID',
  foreign key(role_id) references role(id)
) comment '用户管理表'  charset = utf8mb4;

create table resources (
  id             int auto_increment  comment '主键id'  primary key,
  module_name    varchar(100)  not null  comment '模块名称',
  parent_id      int(11)  not null  comment '父模块ID',
  uri            varchar(128) default null  comment 'uri',
  admin          tinyint(1)   default 0  comment '管理员权限 1有权限 0无权限',
  manager_one    tinyint(1)   default 0  comment '高级用户1权限 1有权限 0无权限',
  manager_two    tinyint(1)   default 0  comment '高级用户2权限 1有权限 0无权限',
  ordinary_user  tinyint(1)   default 0 comment '普通用户权限 1有权限 0无权限'
) comment '资源管理表'  charset = utf8mb4;

后端权限控制
后端主要做两件事:1.对uri的权限进行控制;2.提供根据姓名获取可访问资源的接口。
uri权限控制
该部分主要通过拦截器控制。

import entity.Resources;
import entity.Role;
import entity.User;
import service.AuthorityService;
import util.UserUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class AuthenticationInterceptor extends HandlerInterceptorAdapter {

    private static final String ADMIN = "admin";
    private static final String MANAGER_ONE = "manager_one";
    private static final String MANAGER_TWO = "manager_two";
    private static final String ORDINARY_USER = "ordinary_user";
    private AuthorityService authorityService;

    public AuthenticationInterceptor(AuthorityService authorityService) {
        super();
        this.authorityService = authorityService;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String uri = request.getRequestURI();
        System.out.println(uri);
        if (checkAuth(uri)) {
            return true;
        }
        // 拦截之后返回没有权限的异常
        Exception e = new RuntimeException("no permission!!!");
        throw e;
//        return false;
    }

    private boolean checkAuth(String uri) {
        Resources resources = authorityService.getResourcesByUri(uri);
        if (resources == null) {
            return true;
        }
        //根据登录信息获取name,需要根据自己的登录系统实现
        String name = UserUtils.getUser().getLogin();
        if (name == null || "".equals(name)) {
            return false;
        }
        List<User> users = authorityService.getRoleListByName(name);
        Set<String> roleSet = new HashSet<>();
        roleSet.add(Constants.ORDINARY_USER);
        if (users != null && users.size() > 0) {
            List<Role> allRoles = authorityService.getAllRoles();
            ConcurrentHashMap<Integer, String> roleMap = new ConcurrentHashMap<>(allRoles.size());
            for (Role role: allRoles) {
                roleMap.put(role.getId(), role.getRoleName());
            }
            for (User user : users) {
                roleSet.add(roleMap.get(user.getRoleId()));
            }
        }
        Set<String> resourcesRole = new HashSet<>();
        if (resources.getAdmin()) {
            resourcesRole.add(ADMIN);
        }
        if (resources.getManagerOne()) {
            resourcesRole.add(MANAGER_ONE);
        }
        if (resources.getManagerTwo()) {
            resourcesRole.add(MANAGER_TWO);
        }
        if (resources.getOrdinaryUser()) {
            resourcesRole.add(ORDINARY_USER);
        }
        int sum = roleSet.size() + resourcesRole.size();
        roleSet.addAll(resourcesRole);
        return sum != roleSet.size();
    }
}

根据姓名获取可访问资源的接口

@Controller
@ResponseBody
public class AuthorityController extends BaseController {
    private static final String ADMIN = "admin";
    private static final String MANAGER_ONE = "manager_one";
    private static final String MANAGER_TWO = "manager_two";
    private static final String ORDINARY_USER = "ordinary_user";

    @Autowired
    private AuthorityService authorityService;

    private final static Logger logger = new Logger(AuthorityController.class);

    @RequestMapping(value = "/authority/getAuthority", method = {RequestMethod.GET})
    private Result getAuthority() {
        List<String> result = new ArrayList<>();
        //根据登录信息获取name的接口需根据自己的登录系统实现
        List<User> userList = authorityService.getRoleListByName(getName());
        Resources resources = new Resources();
        if (userList != null && userList.size() > 0) {
            List<Role> roleList = authorityService.getAllRoles();
            Map<Integer, String> roleMap = new HashMap<>(roleList.size());
            for (Role role: roleList) {
                roleMap.put(role.getId(), role.getRoleName());
            }
            for (User user: userList) {
                String roleStr = roleMap.get(user.getRoleId());
                if (ADMIN.equals(roleStr)) {
                    resources.setAdmin(true);
                } else if (MANAGER_ONE.equals(roleStr) || MANAGER_TWO.equals(roleStr)){
                    if (MANAGER_ONE.equals(roleStr)) {
                        resources.setManagerOne(true);
                    }
                    if (MANAGER_TWO.equals(roleStr)) {
                        resources.setManagerTwo(true);
                    }
                } else {
                    resources.setOrdinaryUser(true);
                }
            }
        }
        List<Resources> resourcesList = authorityService.getAllResourcesByRole(resources);
        result = generateAuthority(resourcesList, 0, "", result);
        return Result.success(result);
    }

    private List<String> generateAuthority(List<Resources> resourcesList, int parentId, String parentStr, List<String> result) {
        if (resourcesList == null || resourcesList.size() == 0) {
            return null;
        }
        resourcesList.stream()
                .filter(c -> c.getParentId() == parentId)
                .forEach(c -> {
                    if (parentId == 0) {
                        result.add(c.getModuleName());
                        result.addAll(generateAuthority(resourcesList, c.getId(), c.getModuleName(), new ArrayList<>()));
                    } else {
                        result.add(parentStr + ":" + c.getModuleName());
                        result.addAll(generateAuthority(resourcesList, c.getId(), parentStr + ":" + c.getModuleName(), new ArrayList<>()));
                    }
                });
        return result;
    }
}

前端Vuex权限控制
所有的数据和操作都是通过vuex全局管理控制的。

使用 authInfo 的接口来获取用户的权限信息(用户可以访问的模块或组件名称)列表,例如:sidebar_a:sidebar_child_a。
利用权限信息列表计算出用户可访问的路由,通过 router.addRoutes 动态挂载这些路由。===>侧边栏
需手动配置页面中组件的权限。===>组件
只需权限控制的组件上添加 v-show="this.checkUserAuth('sidebar_b:button_c')"
router/index.js
页面在初始化时加载所有人都可以访问的路由:constantRoutes
动态路由通过增加meta字段来控制,用router.addRoutes动态挂载

export const constantRoutes = [
  {
    path: '/callback',
    component: SSOCallback,
    name: 'sso回调页面',
    hidden: true
  },
  {
    path: '/api/test_b',
    component: SidebarB
  }
];

export const asyncRoutes = [
  {
    path: '/api/test_a',
    component: SidebarA,
    meta: {
      authStr: 'sidebar_a'
    },
    children: [
      {
        path: '/child_a',
        component: SidebarChildA,
        meta: {
          authStr: 'sidebar_a:sidebar_child_a'
       }
    ]
  },
    {
    path: '/api/test_b',
    component: SidebarB,
    meta: {
      authStr: 'sidebar_b'
    }
  }
];

const createRouter = () => new Router({
    routes: constantRoutes
});
const router = createRouter();
export default router;

main.js

Vue.prototype.checkUserAuth = function(name) {
    try {
        let authList = sessionStorage.getItem('authList');
        return authList.indexOf(name) !== -1;
    } catch (e) {
        console.log(e);
    }
    return false;
};

var getRouter;

function hasPermission(authList, route) {
    if (route.meta && route.meta.authStr) {
        return authList.some(auth => route.meta.authStr === auth);
    }
    return true;
}

export function filterAsyncRoutes(routes, authList) {
    const res = [];
    routes.forEach(route => {
        const tmp = route;
        if (hasPermission(authList, tmp)) {
            if (tmp.children) {
                tmp.children = filterAsyncRoutes(tmp.children, authList);
            }
            res.push(tmp);
        }
    });
    return res;
}

function saveObjArr(name, data) {
    console.log(JSON.stringify(data));
    window.sessionStorage.setItem(name, JSON.stringify(data));
}

function getObjArr(name) {
    return JSON.parse(window.sessionStorage.getItem(name));
}

function routerGo(to, next) {
    let authList = getObjArr('authList');
    authList = Array.from(authList);
    let routes = Array.from(asyncRoutes);
    getRouter = filterAsyncRoutes(routes, authList);
    router.options.routes = getRouter;
    router.addRoutes(getRouter);
    // global.antRouter = getRouter;
    next({ ...to, replace: true });
}

router.beforeEach(async(to, from, next) => {
    console.log('getRouter' + getRouter);
    if (!getRouter) {
        let authList = [];
        console.log(store.state.auth.length === 0);
        if (store.state.auth.length === 0) {
            const res = await store.dispatch('getAuthInfo');
            console.log('res:' + res);
            authList = res.data.data.items;
        } else {
            authList = store.state.auth.authList;
        }
        console.log(authList);
        saveObjArr('authList', authList);
        routerGo(to, next);
    } else {
        next();
    }
});