Simple JPA implementation of RBAC model-single table and multi-table query

Table of Contents

concept

Specific implementation of JPA

1. Introduce dependencies

2. Domain module configuration yml file

3. Entity class (take permission table as an example)

4. User module configuration yml file

5. Dao layer interface

6. Service layer interface and implementation class (take UserService as an example)

7. Controller control layer

8. Unit testing

9. Add @EntityScan to the startup class to introduce the entity class package


Concept

Role-Based Access Control, which includes users/roles/permissions.

1. Users are the main body that initiates operations. They can be divided into 2B and 2C users by type. They can be users of the backend management system, internal employees of the OA system, or users facing C-sides. , such as Alibaba Cloud users.

2. Roles act as a bridge, connecting the relationship between users and permissions. Each role can be associated with multiple permissions. At the same time, a user is associated with multiple roles, so this user has multiple roles. multiple permissions.

A role can be associated with multiple users. The administrator only needs to assign the role to the user, and the user will have all the permissions under the role. This design not only improves efficiency, but also has great scalability.

3. Permissions:
It is a resource that users can access, including page permissions, operation permissions, and data permissions:

  • Page permissions:
    That is, the pages that users can see when logging into the system are controlled by menus. The menus include first-level menus and second-level menus. As long as the user has permissions for the first-level and second-level menus, the user can access the page.
  • Operation permissions:
    That is, the function buttons of the page include view, add, modify, delete, review, etc. When the user clicks the delete button, the background will verify whether all permissions under the user role include the delete permission. If it is, you can proceed to the next step, otherwise it will prompt that you have no permission.

Some systems require “visible and operable”, which means that if the operation button can be seen on the page, then the user can operate it. To realize this requirement, the front-end needs to cooperate. The front-end development caches the user’s permission information. The page determines whether the user has this permission. If so, the button is displayed. If not, the button is hidden. In actual scenarios, you can choose whether you need to do this, which will help improve user experience.

  • Data permissions:
    Data permission means that the data users see on the same page are different. For example, the Finance Department can only see the user data under its department, and the Human Resources Department can only see the data of the Human Resources Department.

JPA specific implementation

1. Introduce dependencies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

2. Domain module configuration yml file

3. Entity class (take permission table as an example)

@Table(name = "privs_tab")
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Privs {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="privs_id")
    private Long id;
    @Column(name="privs_name")
    private String name;
    @Column(name="privs_desc")
    private String desc;

    @Column(name="privs_create_by")
    private String createBy;
    @Column(name="privs_create_time")
    private Date createTime;
    @Column(name="privs_update_time")
    private Date updateTime;
}

4. User module configuration yml file

server:
  port: 9099

spring:
  application:
    name: bms-user
#Shield the automatic startup of multiple data sources of mybatisplus
  autoconfigure:
    exclude: com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration
logging:
  level:
    com.wnhz.bms.user: debug

5. Dao layer interface

@Repository
public interface PrivsDao extends JpaRepository<Privs,Long> {
}
@Repository
public interface UserDao extends JpaRepository<User,Long> {

    //Query the user's permissions privs based on the user's username and password
    User findByUsernameAndPassword(String username,String password);
}
@Repository
public interface RoleDao extends JpaRepository<Role,Long> {
}
@Repository
public interface RolePrivsDao extends JpaRepository<RolePrivs,Long> {

    @Query(value = "SELECT * FROM rp_tab WHERE rp_role_id=?",nativeQuery = true)
    List<RolePrivs> findRpsByRoleId(Long roleId);
}

6. Service layer interface and implementation class (take UserService as an example)

public interface UserService {

    //Query the user's permissions privs based on the user's username and password
    List<Privs> findUserPrivs(String username, String password);

    //Full query
    List<User> findAllUsers();

    //delete
    void deleteUser(Long id);

    //Use jpa to query a user's role name and permissions
    UserVo findUserRoleNameAndPrivs(String username, String password);

}
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;
    @Autowired
    private RoleDao roleDao;
    @Autowired
    private RolePrivsDao rolePrivsDao;
    @Autowired
    private PrivsDao privsDao;

    //Query the user's permissions privs based on the user's username and password
    @Override
    public List<Privs> findUserPrivs(String username, String password) {

        List<Privs> privsList = new ArrayList<>();

        User user = userDao.findByUsernameAndPassword(username, password);
        Long roleId = user.getRoleId();

        List<RolePrivs> rpsByRoleId = rolePrivsDao.findRpsByRoleId(roleId);

        rpsByRoleId.forEach(rolePrivs -> {
            Long privsId = rolePrivs.getPrivsId();
            privsList.add(privsDao.findById(privsId).get());
        });

        return privsList;
    }

    //Full query
    //@Cacheable(cacheNames = "findAllUsers") //Put it into the cache after the first query
    @CachePut(cacheNames = "findAllUsers") //Enter the cache for each query
    @Override
    public List<User> findAllUsers() {
        return userDao.findAll();
    }

    //delete
    @CacheEvict(cacheNames = "findAllUsers",key = "#id")
    @Override
    public void deleteUser(Long id) {
        userDao.deleteById(id);
    }

    //Use jpa to query a user's role name and permissions privs
    @Override
    public UserVo findUserRoleNameAndPrivs(String username, String password) {

        List<Privs> privsList = new ArrayList<>(); //Create an empty permission list privsList to store the queried permission information

        User user = userDao.findByUsernameAndPassword(username, password); //Query user information based on username and password,
        Long roleId = user.getRoleId(); //And get the user's role ID.

        List<RolePrivs> rpsByRoleId = rolePrivsDao.findRpsByRoleId(roleId); //Query the role permission relationship list based on role ID

        rpsByRoleId.forEach(rolePrivs -> { //Traverse the role permission relationship list
            Long privsId = rolePrivs.getPrivsId(); //Get permission ID
            privsList.add(privsDao.findById(privsId).get()); //Query the corresponding permission object based on the permission ID and add it to the permission list privsList
        });

        Role role = roleDao.findById(roleId).get(); //Query the role object based on the role ID
        UserVo userVo = new UserVo(); //Create a UserVo object
        //Set the queried user information, role information and permission list information to the corresponding attributes in the UserVo object.
        userVo.setUser(user);
        userVo.setRole(role);
        userVo.setPrivs(privsList);
        //Return the encapsulated UserVo object
        return userVo;
    }
}

7. Controller control layer

@RestController
@RequestMapping("/api/user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/findAllUsers")
    public HttpResp<List<User>> findAllUsers(){
        return HttpResp.success(userService.findAllUsers());
    }

    @DeleteMapping("rmUser")
    public HttpResp rmUser(Long id){
        userService.deleteUser(id);
        return HttpResp.success("Delete user" + id + "Success");
    }
}

8. Unit test

@SpringBootTest
@RunWith(SpringRunner.class)
public class UserServiceImplTest {

    @Autowired
    private UserService userService;

    @Test
    public void findUserPrivs() {
        List<Privs> list = userService.findUserPrivs("jpa", "123");
        list.forEach(e-> System.out.println(e.getName()));
    }

    //Use jpa to query a user's role name and permissions
    @Test
    public void findUserRoleNameAndPrivs() {
        UserVo jpa = userService.findUserRoleNameAndPrivs("jpa", "123");
        System.out.println(jpa.getRole().getName() + "-" + jpa.getPrivs().toString());
    }
}

9. Add @EntityScan to the startup class to introduce the package of entity classes

@SpringBootApplication
@EntityScan(basePackages = "com.****.bms.domain.entity.jpa")
@EnableCaching //Enable spring cache
public class UserApp {
    public static void main(String[] args) {
        SpringApplication.run(UserApp.class);
    }
}

refer to:

https://www.cnblogs.com/javawenjun/p/14884732.html

Learn more about RBAC (Role-Based Access Control) – Zhihu

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Java Skill TreeHomepageOverview 137802 people are learning the system