基于session设计一个RBAC项目

本文介绍了如何基于RBAC模型实现权限管理,包括设计用户实体类、角色实体类和资源实体类,以及它们之间的关系。通过示例展示了如何模拟数据和创建拦截器来检查用户访问权限。最后,提供了登录接口和不同资源接口的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

RBAC模型(Role-Based Access Control:基于角色的访问控制)是早期要提出的基于用户而实现权限控制的一个理论,目前大部分的框架也都是基于RBAC的理论去实现权限的控制;

上篇文章我们使用springsecurity 实现了我们web项目的登录认证和权限管理,本篇文章我们就自己去大家一个简单的权限管理的RBAC项目;

首先我们需要知道实现权限管理,我们大致需要哪些类;

1.用户实体类(里边添加用户名,以及用户密码);

2.角色实体类(里边添加,角色id和角色名 字段);

3.资源实体类(里边有资源id,资源类型,资源名称字段);

然后我们需要理清实体类之间的关系;首先,一个用户会拥有自己的角色,比如说 王强 用户在公司任职 CEO CEO就是一个角色;然后每个用户下边有自己的工作经理,任职部门,出生年月,姓名等等,这些成为该用户的资源info,当然有的用户角色不止一个,所以该用户的资源根据角色的不同也会不相同,因此角色下边也会有资源;

这样我们就可以设计我们的实体类了;

资源实体类下边是不包含其他的类的,所以我们先设计资源实体类:

ResourcesBean 资源实体类:

//资源实体类
public class ResourcesBean {
    private String resourceId;
    private String resourceType;
    private String resourceName;
//下边写set get construtor 方法;

接下来是roleBean 角色实体类:但是我们的角色下边是有资源的,因此要与资源实体类有关联,这边我们使用list集合把资源注入到我们的角色实体类当中:

/*
* 角色实体类
* */
public class RoleBean {
private  String roleId;
private String roleName;
private List<ResourcesBean> resources;//给角色注入资源(userinfo);
//下边为set  get construtor 方法

接下来就是我们的用户实体类 UserBean: 用户实体类既要与我们的角色实体类关联,也要与我们的资源实体类关联;同样我们也使用 list集合注入 rolelist 和 resourceslist;

 

/*
* 用户实体类
* */
public class UserBean {
    private String userId;
    private String userName;
    private String userPass;
    private List<RoleBean> userRoles = new ArrayList<>();
    private List<ResourcesBean> resourceBeans = new ArrayList<>();

这样我们的一个权限认证的实体类就设计完成了

接下来我们需要给我们的实体类添加上数据,并加上关系(项目之中都是需要连接数据库去查询 用户名,账号,角色,资源),在这里我们直接赋值来模拟数据库查询;

创建TestData :

package com.example.demo.entity;

import com.example.demo.bean.ResourcesBean;
import com.example.demo.bean.RoleBean;
import com.example.demo.bean.UserBean;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class TestData {
    private List<UserBean> allUser;
    /**
     * 模拟数据库获取到的数据。
     * admin用户 拥有admin角色,拥有mobile和salary两个资源。
     * mobile用户,拥有mobile角色,拥有mobile资源。
     * worker用户,拥有worker角色,没有资源。
     * @return
     */
private  List<UserBean> getAllUser(){
//    如果该用户不为空,
    if (null ==allUser){
        allUser =new ArrayList<>();
        //资源添加mobile 和salary 资源
        ResourcesBean mobileResource=new ResourcesBean("1","mobile");
        ResourcesBean salaryResource=new ResourcesBean("2","salary");
        List<ResourcesBean> adminResource=new ArrayList<>();
//        将mobile salary资源存入到我们的资源集合adminResource当中
        adminResource.add(salaryResource);
        adminResource.add(mobileResource);
//        只将mobile资源存入到我们的资源集合 managerResources
        List<ResourcesBean> managerResources = new ArrayList<>();
        managerResources.add(mobileResource);
//        admin 有mobile 角色 并且拥有上边 adminResource的两个资源
        RoleBean adminRole = new RoleBean("1","admin");
        adminRole.setResources(adminResource);

//        mobile用户具有 mobile角色,并且具有mobile资源
        RoleBean managerRole = new RoleBean("2","mobile");
        managerRole.setResources(managerResources);
//work具有work 
        RoleBean workRole = new RoleBean("3","w");
List<RoleBean> adminRoles=new ArrayList<>();
adminRoles.add(adminRole);
List<RoleBean> managerRoles=new ArrayList<>();
managerRoles.add(managerRole);


        List<RoleBean> workRoles=new ArrayList<>();
        workRoles.add(workRole);
        UserBean admin = new UserBean("1","admin","admin");
        admin.setUserRoles(adminRoles);
        admin.setResourceBeans(adminResource);
        UserBean mobile = new UserBean("2","manager","manager");
        mobile.setUserRoles(managerRoles);
        mobile.setResourceBeans(managerResources);
        UserBean work = new UserBean("3","worker","worker");
        work.setUserRoles(workRoles);
        allUser.add(admin);
        allUser.add(mobile);
        allUser.add(work);
    }
    return allUser;
}
/*
* 判断用户的账号和密码是否正确
* */
    public UserBean qeryUser(UserBean user){
        List<UserBean> allUser = this.getAllUser();
//        将用户集合遍历 判断登录是否正确
        List<UserBean> userList = allUser.stream().filter(userBean ->
                userBean.getUserName().equals(user.getUserPass())
                        &&
                        userBean.getUserPass().equals(user.getUserPass())
        ).collect(Collectors.toList());
        return userList.size()>0?userList.get(0):null;
    }



}

接下来就是创建我们的拦截器,所有访问的接口都要跳转到 登录页面 进行登录,获取会话session;

 首先先创建我们的路由枚举常量,方便后边的代码编写;

package com.example.demo.constants;

public class MyConstants {
//    设置 枚举常量
    public static final String FLAG_CURRENTUSER = "currentUser";
    public static final String RESOURCE_COMMON = "common";
    public static final String RESOURCE_MOBILE = "mobile";
    public static final String RESOURCE_SALARY = "salary";
}

 拦截器配置:

package com.example.demo.config;

import com.example.demo.bean.UserBean;
import com.example.demo.constants.MyConstants;
import com.sun.xml.internal.ws.handler.HandlerException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;


@Component
public class AuthInterceptor implements HandlerInterceptor {

//授权拦截
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//        不需要登录 就可以访问的路径
    String requestURI =request.getRequestURI();

    if (requestURI.contains(".")|| requestURI.startsWith("/"+ MyConstants.RESOURCE_COMMON+"/")){
        return  true;

    }
//    未登录用户,直接拒绝访问
//        获取用户的属性 并进行判断是否为空
        if ((null == request.getSession().getAttribute(MyConstants.FLAG_CURRENTUSER))) {
//如果不为空设置response 的返回使用utf-8的编码样式
            response.setCharacterEncoding("UTF-8");
            /*
            * 返回打印字符串 please login first
            * */
            response.getWriter().write("please login first");
            return  false;
        }else {
            UserBean currentUser =(UserBean) request.getSession().getAttribute(MyConstants.FLAG_CURRENTUSER);
//            已登录用户,判断是否又资源访问权限
//            如果用户的请求地址是mobile,而且用户又该接口的访问权限
            if (requestURI.startsWith("/"+MyConstants.RESOURCE_MOBILE+"/")&&currentUser.havaPermission(MyConstants.RESOURCE_MOBILE)){
                return  true;
//                如果用户访问的是salary接口 并且该用户具有权限
            }else if (requestURI.startsWith("/"+MyConstants.RESOURCE_SALARY+"/")&& currentUser.havaPermission(MyConstants.RESOURCE_SALARY)){

                return  true;
            }else {
//                如果用户不具备权限 或者请求地址不对 就返回打印出 no auth to visit;
                response.setCharacterEncoding("UTF-8");
                response.getWriter().write("no auth to visit");
                return  false;
            }

        }


    }
}
package com.example.demo.config;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.Resource;
/*
* 配置拦截器和页面跳转
*
* */
@Component
public class MyWebAppConfigurer  implements WebMvcConfigurer {
    @Resource
    private  AuthInterceptor authInterceptor;
//配置权限拦截:拦截所有请求
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor).addPathPatterns("/**");

    }
//简单配置启动页面 所有页面首先跳转至我们的登录页面

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("redirect:/index.html");
    }


}

配置完拦截器,我们需要配置一下我们的登录接口:

package com.example.demo.controller;

import com.example.demo.bean.UserBean;
import com.example.demo.constants.MyConstants;
import com.example.demo.service.AuthService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.logging.Logger;
/*
* 登录页面配置
* */
@RestController
@RequestMapping("/common")
public class loginController {
    /*
    * 因为是登陆页面 我们设置本类的日志 ->可以向控制台打印日志
    *
    * */
    private  final Logger logger= (Logger) LoggerFactory.getLogger(this.getClass());

@Resource
private AuthService authService;
    @PostMapping("/login")
    public UserBean login(UserBean loginUser, HttpServletRequest request){
        UserBean user = authService.userLogin(loginUser);
        if(null != user){
            logger.info("user login succeed");
            request.getSession().setAttribute(MyConstants.FLAG_CURRENTUSER,user);
        }
        logger.info("user login failed");
        return user;
    }
//    获取当前用户
    @PostMapping("/getCurrentUser")
    public Object getCurrentUser(HttpSession session){
        return session.getAttribute(MyConstants.FLAG_CURRENTUSER);
    }
    @PostMapping("/logout")
//    注销
    public void logout(HttpSession session){
        session.removeAttribute(MyConstants.FLAG_CURRENTUSER);

}

}

接下来是我们的资源接口 mobile 和salary接口;

package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/mobile")
public class MobileController {
    @GetMapping ("/query")
    public String query(){
        return  "mobile";
    }
}
package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/salary")
public class SalaryController {
    @GetMapping("/query")
    public  String query(){
        return "salary";
    }
}

这样呢简单的一套后端RBAC项目后端就编写完成了;我们登录不同的用户会有不同的资源权限!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灰灰的996

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值