SpringBoot integrates spring security to realize permission control: user management

Catalogue of series articles SpringBoot integrates SpringSecurity to realize permission control (I): implementation prin...
2.1 create user entity class
2.2 create user role entity class
2.3 add user and user role Mapper interface
2.4 add, delete, modify and query services for users
2.5 writing Controller layer
3.1 add user api access interface
3.2 compiling front page

Catalogue of series articles
SpringBoot integrates SpringSecurity to realize permission control (I): implementation principle
SpringBoot integrates spring security to realize permission control (II): Design of basic model of permission data
SpringBoot integrates SpringSecurity to achieve permission control (3): front end dynamic loading routing and menu
SpringBoot integrates SpringSecurity to achieve permission control (IV): role management

1, Foreword

The user of the system is called a user, and can only operate the system within the scope of authority granted.
Administrator is a special user with the highest authority of system operation.

  • The results are as follows:
2, Backend implementation

2.1 create user entity class

  • This entity class corresponds to the user table and records the user's basic information.
/** * User table * * @author zhuhuix * @date 2020-04-03 */ @ApiModel(value = "User information") @Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor @TableName("sys_user") public class SysUser implements Serializable { @TableId(value = "id", type = IdType.AUTO) private Long id; private String userName; @JsonIgnore private String password; private String nickName; /** * Gender 0 - unknown, 1-male,2-female */ private Integer gender; /** * Avatar address */ private String avatarUrl; private String country; private String province; private String city; @Email private String email; private String phone; private String remarks; @TableLogic private Boolean enabled; private Timestamp lastPasswordResetTime; private Timestamp createTime; @Builder.Default private Timestamp updateTime = Timestamp.valueOf(LocalDateTime.now()); }

2.2 create user role entity class

  • The entity class corresponds to the user role table and records the user's corresponding role information (one corner user can correspond to multiple roles).
/** * User role table * * @author zhuhuix * @date 2021-09-29 */ @ApiModel(value = "User role information") @Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor @TableName("sys_user_role") public class SysUserRole { @TableId(value = "id", type = IdType.AUTO) private Long id; private Long userId; private Long roleId; private Timestamp createTime; }

2.3 add user and user role Mapper interface

  • User entities and user role entities can be operated through the Mapper interface
/** * User DAO interface * * @author zhuhuix * @date 2021-07-19 */ @Mapper public interface SysUserMapper extends BaseMapper<SysUser> { /** * Query user roles * @param userId User id * @return Role information */ @Select("select r.id,r.role_code,r.role_name,r.description,r.enabled,r.create_time,r.update_time " + "from sys_role r " + "INNER JOIN sys_user_role ur ON r.id=ur.role_id where ur.user_id=# ") List<SysRole> selectUserRoles(Long userId); /** * Query user permissions * @param userId User id * @return permissions information */ @Select("SELECT m.id, m.`path`, m.`name`, m.`component`, m.`icon`, m.`cache`, m.`hidden`, m.`redirect`, m.p_id " + "FROM " + "sys_menu m " + "INNER JOIN sys_permission p ON p.menu_id = m.id " + "INNER JOIN sys_user_role ur ON ur.role_id = p.role_id " + "INNER JOIN sys_user u ON u.id = ur.user_id " + "INNER JOIN sys_role r ON r.id = ur.role_id where ur.user_id=#"+ " and m.enabled=1 " + " order by m.sort " ) List<PermissionDto> selectUserPermission(Long userId); }
/** * User role DAO interface * * @author zhuhuix * @date 2021-09-29 */ @Mapper public interface SysUserRoleMapper extends BaseMapper<SysUserRole> { }

2.4 add, delete, modify and query services for users

/** * User management service interface * * @author zhuhuix * @date 2020-04-03 */ public interface SysUserService { /** * Add user * * @param user Users to be added * @return Add successful users */ SysUser create(SysUser user); /** * delete user * * @param user Users to be deleted * @return Delete successful users */ SysUser delete(SysUser user); /** * Modify user * * @param user User to be modified * @return User successfully modified */ SysUser update(SysUser user); /** * Find users by id * * @param id User id * @return User information */ SysUser findById(Long id); /** * Find users by userName * * @param userName User account * @return User corresponding to user account */ SysUser findByUserName(String userName); /** * Determine whether the registered mailbox exists * * @param email Mailbox number * @return Found */ boolean registerEmailExist(String email); /** * Get user information * * @return User information */ UserDetails getUserInfo(); /** * Modify user Avatar * * @param file file * @return json */ Map<String, String> updateAvatar(MultipartFile file); /** * Get user role information * * @param userId User id * @return Role information */ List<SysRole> getUserRoles(Long userId); /** * Save user role * * @param userId User id * @param roleIds Role id list * @return Is it successful */ Boolean saveUserRoles(Long userId,Set<Long> roleIds); /** * Get user permission information * * @param userId User id * @return permissions information */ List<PermissionDto> getUserPermission(Long userId); /** * Query user information according to criteria * * @param sysUserQueryDto query criteria * @return User list */ List<SysUser> list(SysUserQueryDto sysUserQueryDto); /** * Batch delete user * * @param ids List of user IDs to be deleted * @return Is it successful */ Boolean delete(Set<Long> ids); }
/** * User management service implementation class * * @author zhuhuix * @date 2020-04-03 */ @Slf4j @Service @RequiredArgsConstructor @Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) public class SysUserServiceImpl implements SysUserService { private final SysUserMapper sysUserMapper; private final SysUserRoleMapper sysUserRoleMapper; private final UploadFileTool uploadFileTool; @Override @Transactional(rollbackFor = Exception.class) public SysUser create(SysUser user) { if (sysUserMapper.insert(user) > 0) { return user; } throw new RuntimeException("Failed to add user information"); } @Override @Transactional(rollbackFor = Exception.class) public SysUser delete(SysUser user) { QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>(); queryWrapper.lambda().eq(SysUser::getUserName, user.getUserName()); if (sysUserMapper.delete(queryWrapper) > 0) { return user; } throw new RuntimeException("Failed to delete user information"); } @Override @Transactional(rollbackFor = Exception.class) public SysUser update(SysUser user) { if (sysUserMapper.updateById(user) > 0) { return user; } throw new RuntimeException("Failed to update user information"); } @Override public SysUser findById(Long id) { return sysUserMapper.selectById(id); } @Override public SysUser findByUserName(String userName) { return sysUserMapper.selectOne(new QueryWrapper<SysUser>().lambda().eq(SysUser::getUserName, userName)); } @Override public boolean registerEmailExist(String email) { QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>(); queryWrapper.lambda().eq(SysUser::getEmail, email); return sysUserMapper.selectOne(queryWrapper) != null; } @Override public UserDetails getUserInfo() { UserDetailsService userDetailsService = SpringContextHolder.getBean(UserDetailsService.class); return userDetailsService.loadUserByUsername(getCurrentLoginUserName()); } @Override @Transactional(rollbackFor = Exception.class) public Map<String, String> updateAvatar(MultipartFile file) { SysUser sysUser = findByUserName(getCurrentLoginUserName()); UploadFile uploadFile = uploadFileTool.upload(sysUser.getUserName(), file.getOriginalFilename(), file); sysUser.setAvatarUrl(uploadFile.getType() + File.separator + uploadFile.getFileName()); update(sysUser); return new HashMap<String, String>(1) {{ put("avatar", uploadFile.getFileName()); }}; } @Override public List<PermissionDto> getUserPermission(Long userId) { return sysUserMapper.selectUserPermission(userId); } @Override public List<SysRole> getUserRoles(Long userId) { return sysUserMapper.selectUserRoles(userId); } @Override @Transactional(rollbackFor = Exception.class) public Boolean saveUserRoles(Long userId, Set<Long> roleIds) { // First, clear the user's original role information QueryWrapper<SysUserRole> queryWrapper = new QueryWrapper<>(); queryWrapper.lambda().eq(SysUserRole::getUserId, userId); sysUserRoleMapper.delete(queryWrapper); // Add again for (Long roleId : roleIds) { SysUserRole sysUserRole = new SysUserRole(); sysUserRole.setUserId(userId); sysUserRole.setRoleId(roleId); sysUserRole.setCreateTime(Timestamp.valueOf(LocalDateTime.now())); sysUserRoleMapper.insert(sysUserRole); } return true; } private String getCurrentLoginUserName() { final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null) { throw new RuntimeException("The login status has expired"); } if (authentication.getPrincipal() instanceof UserDetails) { UserDetails userDetails = (UserDetails) authentication.getPrincipal(); return (userDetails.getUsername()); } throw new RuntimeException("The information for the current login cannot be found"); } @Override public List<SysUser> list(SysUserQueryDto sysUserQueryDto) { QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>(); if (!StringUtils.isEmpty(sysUserQueryDto.getUserName())) { queryWrapper.lambda().like(SysUser::getUserName, sysUserQueryDto.getUserName()) .or().like(SysUser::getNickName, sysUserQueryDto.getUserName()); } if (!StringUtils.isEmpty(sysUserQueryDto.getCreateTimeStart()) && !StringUtils.isEmpty(sysUserQueryDto.getCreateTimeEnd())) { queryWrapper.and(wrapper -> wrapper.lambda().between(SysUser::getCreateTime, new Timestamp(sysUserQueryDto.getCreateTimeStart()), new Timestamp(sysUserQueryDto.getCreateTimeEnd()))); } return sysUserMapper.selectList(queryWrapper); } @Override @Transactional(rollbackFor = Exception.class) public Boolean delete(Set<Long> ids) { if (sysUserMapper.deleteBatchIds(ids) > 0) { return true; } throw new RuntimeException("Failed to delete user information"); } }

2.5 writing Controller layer

  • The following 9 background interfaces are implemented:
/** * api User information * * @author zhuhuix * @date 2021-08-16 */ @Slf4j @RestController @AllArgsConstructor @RequestMapping("/api/user") @Api(tags = "User information interface") public class SysUserController { private final SysUserService sysUserService; @ApiOperation("Get current login user information") @GetMapping() public ResponseEntity<Object> getUserInfo() { return ResponseEntity.ok(sysUserService.getUserInfo()); } @ApiOperation("according to id Get user information") @GetMapping("/") public ResponseEntity<Object> getUserInfo(@PathVariable Long id) { return ResponseEntity.ok(sysUserService.findById(id)); } @ApiOperation("Update user information") @PostMapping() public ResponseEntity<Object> saveUser(@RequestBody SysUser user) { return ResponseEntity.ok(sysUserService.update(user)); } @PreAuthorize("hasAuthority('user:updateAvatar')") @ApiOperation("Modify user Avatar") @PostMapping(value = "/updateAvatar") public ResponseEntity<Object> updateAvatar(@RequestParam MultipartFile avatar) { return ResponseEntity.ok(sysUserService.updateAvatar(avatar)); } @ApiOperation("Query user list by criteria") @PostMapping("/list") public ResponseEntity<Object> getSysUserList(@RequestBody SysUserQueryDto sysUserQueryDto) { return ResponseEntity.ok(sysUserService.list(sysUserQueryDto)); } @ApiOperation("Batch delete user") @DeleteMapping public ResponseEntity<Object> deleteUsers(@RequestBody Set<Long> ids) { return ResponseEntity.ok(sysUserService.delete(ids)); } @ApiOperation("Get user role") @GetMapping("/roles/") public ResponseEntity<Object> getUserRoles(@PathVariable Long userId) { return ResponseEntity.ok(sysUserService.getUserRoles(userId)); } @ApiOperation("Save user role") @PostMapping("/roles/") public ResponseEntity<Object> saveUserRoles(@PathVariable Long userId, @RequestBody Set<Long> ids) { return ResponseEntity.ok(sysUserService.saveUserRoles(userId, ids)); } @ApiOperation("Get user permissions") @GetMapping("/permission/") public ResponseEntity<Object> getUserPermission(@PathVariable Long userId) { return ResponseEntity.ok(sysUserService.getUserPermission(userId)); } }
3, Front end implementation

3.1 add user api access interface

import request from '@/utils/request' // Sign in export function login(data) { return request({ url: '/api/auth/login', method: 'post', data }) } // cancellation export function logout() { return request({ url: '/api/auth/logout', method: 'delete' }) } // Get current login user information export function getInfo() { return request({ url: '/api/user', method: 'get' }) } // Obtain user information according to user id export function getInfoById(id) { return request({ url: '/api/user/' + id, method: 'get' }) } // Save and update users export function saveUser(data) { return request({ url: '/api/user', method: 'post', data }) } // Batch delete users according to user id list export function deleteUser(ids) { return request({ url: '/api/user', method: 'delete', data: ids }) } // Get user list according to condition query export function getUserList(params) { return request({ url: '/api/user/list', method: 'post', data: JSON.stringify(params) }) } // Obtain user permissions according to user id export function getUserPermission(userId) { return request({ url: '/api/user/permission/' + userId, method: 'get' }) } // Get user role export function getUserRoles(userId) { return request({ url: '/api/user/roles/' + userId, method: 'get' }) } // Assign user roles export function saveUserRoles(userId, roleIds) { return request({ url: '/api/user/roles/' + userId, method: 'post', data: roleIds }) }

3.2 compiling front page

  • We need to write a complete page:
  1. Query users by login account or user name, registration start and end time, and display them in the form of list.

  2. Click the "assign role" button to pop up the form and select role information to assign roles to users.

  3. Select a user from the list (multiple choices are allowed), and click "delete" to delete the selected user. There should be a prompt before deleting.

  • The key source codes of the front end are as follows:
    – src/user/index.vue
<template> <div> <!--toolbar--> <div> <!-- search --> <el-input v-model="userName" size="small" clearable placeholder="Enter account or user name to search" style="width: 200px" @keyup.enter.native="doQuery" /> <el-date-picker v-model="createTime" :default-time="['00:00:00', '23:59:59']" type="daterange" range-separator=":" size="small" value-format="yyyy-MM-dd HH:mm:ss" start-placeholder="Start date" end-placeholder="End date" /> <el-button size="mini" type="success" icon="el-icon-search" @click="doQuery" >search</el-button> <el-button size="mini" type="danger" icon="el-icon-circle-plus-outline" :disabled="selections.length===0" @click="doDelete" >delete</el-button> </div> <el-row> <!--Role assignment form--> <el-dialog append-to-body :close-on-click-modal="false" :visible.sync="showDialog" title="Role assignment" width="600px"> <el-form ref="form" :inline="true" :model="form" size="small" label-width="76px"> <el-form-item label="Login account" prop="userName"> <el-input v-model="form.userName" :disabled="true" /> </el-form-item> <el-form-item label="nickname" prop="nickName"> <el-input v-model="form.nickName" :disabled="true" /> </el-form-item> <el-form-item style="margin-bottom: 0;" label="role" prop="userRoles"> <el-select v-model="userRoles" style="width: 455px" multiple filterable placeholder="Please select" @remove-tag="deleteTag" @change="changeRole" > <el-option v-for="item in roles" :key="item.roleCode" :label="item.roleName" :value="item.id" /> </el-select> </el-form-item> </el-form> <div slot="footer"> <el-button type="text" @click="doCancel">cancel</el-button> <el-button :loading="formLoading" type="primary" @click="doSubmit">confirm</el-button> </div> </el-dialog> <el-tabs v-model="activeName" type="border-card"> <el-tab-pane label="User list" name="userList"> <el-table ref="table" v-loading="loading" :data="users" style="width: 100%; font-size: 12px;" @selection-change="selectionChangeHandler"> <el-table-column type="selection" width="55" /> <el-table-column :show-overflow-tooltip="true" width="150" prop="userName" label="Login account" /> <el-table-column :show-overflow-tooltip="true" width="150" prop="nickName" label="User nickname" /> <el-table-column prop="gender" width="60" label="Gender"> <template slot-scope="scope"> <el-tag v-if="scope.row.gender===1" type="success">male</el-tag> <el-tag v-if="scope.row.gender===2" type="warning">female</el-tag> <el-tag v-if="scope.row.gender===0" type="info">unknown</el-tag> </template> </el-table-column> <el-table-column :show-overflow-tooltip="true" prop="phone" width="150" label="Telephone" /> <el-table-column :show-overflow-tooltip="true" prop="city" label="Location"> <template slot-scope="scope"> <span>{{ scope.row.province }} {{ scope.row.city }} {{ scope.row.country }}</span> </template> </el-table-column> <el-table-column :show-overflow-tooltip="true" prop="avatarUrl" width="80" label="head portrait"> <template slot-scope="scope"> <img :src=" scope.row.avatarUrl ? baseApi + '/file/' + scope.row.avatarUrl : Avatar " > </template> </el-table-column> <el-table-column :show-overflow-tooltip="true" prop="createTime" width="155" label="Date of registration"> <template slot-scope="scope"> <span>{{ parseTime(scope.row.createTime) }}</span> </template> </el-table-column> <el-table-column label="operation" width="160" align="center" fixed="right" > <template slot-scope="scope"> <el-button size="mini" type="text" round @click="doAssignRole(scope.row.id)">Assign roles</el-button> </template> </el-table-column> </el-table> </el-tab-pane> </el-tabs> </el-row> </div> </template> <script> import { mapGetters } from 'vuex' import Avatar from '@/assets/images/avatar.png' import { parseTime } from '@/utils/index' import { getUserList, deleteUser, getInfoById, getUserRoles, saveUserRoles } from '@/api/user' import { getRoleList } from '@/api/role' export default { name: 'User', data() { return { Avatar: Avatar, activeName: 'userList', showDialog: false, loading: false, formLoading: true, form: {}, users: [], selections: [], userName: '', createTime: null, roles: [], userRoles: [] } }, computed: { ...mapGetters([ 'baseApi' ]) }, created() { }, methods: { parseTime, doQuery() { this.users = [] var param = { userName: this.userName } if (this.createTime != null) { param.createTimeStart = Date.parse(this.createTime[0]) param.createTimeEnd = Date.parse(this.createTime[1]) } getUserList(param).then(res => { if (res) { this.users = res } }) }, doDelete() { const ids = [] this.selections.forEach((res) => { ids.push(res.id) }) this.$confirm(`Are you sure to delete these users?`, 'Tips', { confirmButtonText: 'determine', cancelButtonText: 'cancel', type: 'warning' }).then(() => deleteUser(ids).then(res => { if (res) { this.$notify({ title: 'Delete succeeded', type: 'success', duration: 2500 }) this.doQuery() } }) ).catch(() => { }) }, // Select change selectionChangeHandler(val) { this.selections = val }, doAssignRole(id) { this.form = {} this.userRoles = [] this.roles = [] this.showDialog = true this.formLoading = true getInfoById(id).then((res) => { this.form = { id: res.id, userName: res.userName, nickName: res.nickName, gender: res.gender, phone: res.phone } var param = { } getRoleList(param).then(res => { if (res) { this.roles = res } getUserRoles(id).then((res) => { if (res) { res.forEach(role => { this.userRoles.push(role.id) }) } this.formLoading = false }) }) }) }, doCancel() { this.showDialog = false this.form = {} }, doSubmit() { this.formLoading = true saveUserRoles(this.form.id, this.userRoles).then(() => { this.showDialog = false this.$notify({ title: 'Saved successfully', type: 'success', duration: 2500 }) }) }, deleteTag(value) { this.userRoles.forEach(function(data, index) { if (data.id === value) { this.userRoles.splice(index, value) } }) }, changeRole(value) { // console.log(this.userRoles) } } } </script> <style rel="stylesheet/scss" lang="scss"> .avatar { width: 32px; height: 32px; border-radius: 50%; } </style> <style rel="stylesheet/scss" lang="scss" scoped> ::v-deep .el-input-number .el-input__inner { text-align: left; } </style>
4, Effect demonstration

5, Source code

7 October 2021, 22:05 | Views: 5090

Add new comment

For adding a comment, please log in
or create account

0 comments