• 在项目中应用SpringSecurity权限控制


    在项目中应用SpringSecurity权限控制

    要进行认证和授权需要前面课程中提到的权限模型涉及的7张表支撑,因为用户信息、权限信息、菜单信息、角色信息、关联信息等都保存在这7张表中,也就是这些表中的数据是我们进行认证和授权的依据。所以在真正进行认证和授权之前需要对这些数据进行管理,即我们需要开发如下一些功能:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XuC0w8rS-1656071032134)(images/image-20220623170722669.png)]

    1、权限数据管理(增删改查)

    2、菜单数据管理(增删改查)

    3、角色数据管理(增删改查、角色关联权限、角色关联菜单)

    4、用户数据管理(增删改查、用户关联角色)

    数据库数据实现导入,简化上面的4步步骤

    DROP TABLE IF EXISTS `t_user`;
    CREATE TABLE `t_user` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `birthday` date DEFAULT NULL,
      `gender` varchar(1) DEFAULT NULL,
      `username` varchar(32) DEFAULT NULL,
      `password` varchar(256) DEFAULT NULL,
      `remark` varchar(32) DEFAULT NULL,
      `station` varchar(1) DEFAULT NULL,
      `telephone` varchar(11) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of t_user
    -- ----------------------------
    INSERT INTO `t_user` VALUES ('1', null, null, 'admin', '$2a$10$u/BcsUUqZNWUxdmDhbnoeeobJy6IBsL1Gn/S0dMxI2RbSgnMKJ.4a', null, null, null);
    INSERT INTO `t_user` VALUES ('2', null, null, 'xiaoming', '$2a$10$3xW2nBjwBM3rx1LoYprVsemNri5bvxeOd/QfmO7UDFQhW2HRHLi.C', null, null, null);
    INSERT INTO `t_user` VALUES ('3', null, null, 'test', '$2a$10$zYJRscVUgHX1wqwu90WereuTmIg6h/JGirGG4SWBsZ60wVPCgtF8W', null, null, null);
    
    DROP TABLE IF EXISTS `t_user_role`;
    CREATE TABLE `t_user_role` (
      `user_id` int(11) NOT NULL,
      `role_id` int(11) NOT NULL,
      PRIMARY KEY (`user_id`,`role_id`),
      KEY `FK_Reference_8` (`role_id`),
      CONSTRAINT `FK_Reference_7` FOREIGN KEY (`user_id`) REFERENCES `t_user` (`id`),
      CONSTRAINT `FK_Reference_8` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of t_user_role
    -- ----------------------------
    INSERT INTO `t_user_role` VALUES ('1', '1');
    INSERT INTO `t_user_role` VALUES ('2', '2');
    
    DROP TABLE IF EXISTS `t_permission`;
    CREATE TABLE `t_permission` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(32) DEFAULT NULL,
      `keyword` varchar(64) DEFAULT NULL,
      `description` varchar(128) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of t_permission
    -- ----------------------------
    INSERT INTO `t_permission` VALUES ('1', '新增检查项', 'CHECKITEM_ADD', null);
    INSERT INTO `t_permission` VALUES ('2', '删除检查项', 'CHECKITEM_DELETE', null);
    INSERT INTO `t_permission` VALUES ('3', '编辑检查项', 'CHECKITEM_EDIT', null);
    INSERT INTO `t_permission` VALUES ('4', '查询检查项', 'CHECKITEM_QUERY', null);
    INSERT INTO `t_permission` VALUES ('5', '新增检查组', 'CHECKGROUP_ADD', null);
    INSERT INTO `t_permission` VALUES ('6', '删除检查组', 'CHECKGROUP_DELETE', null);
    INSERT INTO `t_permission` VALUES ('7', '编辑检查组', 'CHECKGROUP_EDIT', null);
    INSERT INTO `t_permission` VALUES ('8', '查询检查组', 'CHECKGROUP_QUERY', null);
    INSERT INTO `t_permission` VALUES ('9', '新增套餐', 'SETMEAL_ADD', null);
    INSERT INTO `t_permission` VALUES ('10', '删除套餐', 'SETMEAL_DELETE', null);
    INSERT INTO `t_permission` VALUES ('11', '编辑套餐', 'SETMEAL_EDIT', null);
    INSERT INTO `t_permission` VALUES ('12', '查询套餐', 'SETMEAL_QUERY', null);
    INSERT INTO `t_permission` VALUES ('13', '预约设置', 'ORDERSETTING', null);
    INSERT INTO `t_permission` VALUES ('14', '查看统计报表', 'REPORT_VIEW', null);
    INSERT INTO `t_permission` VALUES ('15', '新增菜单', 'MENU_ADD', null);
    INSERT INTO `t_permission` VALUES ('16', '删除菜单', 'MENU_DELETE', null);
    INSERT INTO `t_permission` VALUES ('17', '编辑菜单', 'MENU_EDIT', null);
    INSERT INTO `t_permission` VALUES ('18', '查询菜单', 'MENU_QUERY', null);
    INSERT INTO `t_permission` VALUES ('19', '新增角色', 'ROLE_ADD', null);
    INSERT INTO `t_permission` VALUES ('20', '删除角色', 'ROLE_DELETE', null);
    INSERT INTO `t_permission` VALUES ('21', '编辑角色', 'ROLE_EDIT', null);
    INSERT INTO `t_permission` VALUES ('22', '查询角色', 'ROLE_QUERY', null);
    INSERT INTO `t_permission` VALUES ('23', '新增用户', 'USER_ADD', null);
    INSERT INTO `t_permission` VALUES ('24', '删除用户', 'USER_DELETE', null);
    INSERT INTO `t_permission` VALUES ('25', '编辑用户', 'USER_EDIT', null);
    INSERT INTO `t_permission` VALUES ('26', '查询用户', 'USER_QUERY', null);
    
    -- ----------------------------
    -- Table structure for `t_role`
    -- ----------------------------
    DROP TABLE IF EXISTS `t_role`;
    CREATE TABLE `t_role` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(32) DEFAULT NULL,
      `keyword` varchar(64) DEFAULT NULL,
      `description` varchar(128) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of t_role
    -- ----------------------------
    INSERT INTO `t_role` VALUES ('1', '系统管理员', 'ROLE_ADMIN', null);
    INSERT INTO `t_role` VALUES ('2', '健康管理师', 'ROLE_HEALTH_MANAGER', null);
    
    -- ----------------------------
    -- Table structure for `t_role_menu`
    -- ----------------------------
    DROP TABLE IF EXISTS `t_role_menu`;
    CREATE TABLE `t_role_menu` (
      `role_id` int(11) NOT NULL,
      `menu_id` int(11) NOT NULL,
      PRIMARY KEY (`role_id`,`menu_id`),
      KEY `FK_Reference_10` (`menu_id`),
      CONSTRAINT `FK_Reference_10` FOREIGN KEY (`menu_id`) REFERENCES `t_menu` (`id`),
      CONSTRAINT `FK_Reference_9` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of t_role_menu
    -- ----------------------------
    INSERT INTO `t_role_menu` VALUES ('1', '1');
    INSERT INTO `t_role_menu` VALUES ('2', '1');
    INSERT INTO `t_role_menu` VALUES ('1', '2');
    INSERT INTO `t_role_menu` VALUES ('2', '2');
    INSERT INTO `t_role_menu` VALUES ('1', '3');
    INSERT INTO `t_role_menu` VALUES ('2', '3');
    INSERT INTO `t_role_menu` VALUES ('1', '4');
    INSERT INTO `t_role_menu` VALUES ('2', '4');
    INSERT INTO `t_role_menu` VALUES ('1', '5');
    INSERT INTO `t_role_menu` VALUES ('1', '6');
    INSERT INTO `t_role_menu` VALUES ('1', '7');
    INSERT INTO `t_role_menu` VALUES ('1', '8');
    INSERT INTO `t_role_menu` VALUES ('1', '9');
    INSERT INTO `t_role_menu` VALUES ('1', '10');
    INSERT INTO `t_role_menu` VALUES ('1', '11');
    INSERT INTO `t_role_menu` VALUES ('1', '12');
    INSERT INTO `t_role_menu` VALUES ('1', '13');
    INSERT INTO `t_role_menu` VALUES ('1', '14');
    INSERT INTO `t_role_menu` VALUES ('1', '15');
    INSERT INTO `t_role_menu` VALUES ('1', '16');
    INSERT INTO `t_role_menu` VALUES ('1', '17');
    INSERT INTO `t_role_menu` VALUES ('1', '18');
    INSERT INTO `t_role_menu` VALUES ('1', '19');
    INSERT INTO `t_role_menu` VALUES ('1', '20');
    INSERT INTO `t_role_menu` VALUES ('1', '21');
    
    -- ----------------------------
    -- Table structure for `t_role_permission`
    -- ----------------------------
    DROP TABLE IF EXISTS `t_role_permission`;
    CREATE TABLE `t_role_permission` (
      `role_id` int(11) NOT NULL,
      `permission_id` int(11) NOT NULL,
      PRIMARY KEY (`role_id`,`permission_id`),
      KEY `FK_Reference_12` (`permission_id`),
      CONSTRAINT `FK_Reference_11` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`),
      CONSTRAINT `FK_Reference_12` FOREIGN KEY (`permission_id`) REFERENCES `t_permission` (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of t_role_permission
    -- ----------------------------
    INSERT INTO `t_role_permission` VALUES ('1', '1');
    INSERT INTO `t_role_permission` VALUES ('2', '1');
    INSERT INTO `t_role_permission` VALUES ('1', '2');
    INSERT INTO `t_role_permission` VALUES ('2', '2');
    INSERT INTO `t_role_permission` VALUES ('1', '3');
    INSERT INTO `t_role_permission` VALUES ('2', '3');
    INSERT INTO `t_role_permission` VALUES ('1', '4');
    INSERT INTO `t_role_permission` VALUES ('2', '4');
    INSERT INTO `t_role_permission` VALUES ('1', '5');
    INSERT INTO `t_role_permission` VALUES ('2', '5');
    INSERT INTO `t_role_permission` VALUES ('1', '6');
    INSERT INTO `t_role_permission` VALUES ('2', '6');
    INSERT INTO `t_role_permission` VALUES ('1', '7');
    INSERT INTO `t_role_permission` VALUES ('2', '7');
    INSERT INTO `t_role_permission` VALUES ('1', '8');
    INSERT INTO `t_role_permission` VALUES ('2', '8');
    INSERT INTO `t_role_permission` VALUES ('1', '9');
    INSERT INTO `t_role_permission` VALUES ('2', '9');
    INSERT INTO `t_role_permission` VALUES ('1', '10');
    INSERT INTO `t_role_permission` VALUES ('2', '10');
    INSERT INTO `t_role_permission` VALUES ('1', '11');
    INSERT INTO `t_role_permission` VALUES ('2', '11');
    INSERT INTO `t_role_permission` VALUES ('1', '12');
    INSERT INTO `t_role_permission` VALUES ('2', '12');
    INSERT INTO `t_role_permission` VALUES ('1', '13');
    INSERT INTO `t_role_permission` VALUES ('2', '13');
    INSERT INTO `t_role_permission` VALUES ('1', '14');
    INSERT INTO `t_role_permission` VALUES ('2', '14');
    INSERT INTO `t_role_permission` VALUES ('1', '15');
    INSERT INTO `t_role_permission` VALUES ('1', '16');
    INSERT INTO `t_role_permission` VALUES ('1', '17');
    INSERT INTO `t_role_permission` VALUES ('1', '18');
    INSERT INTO `t_role_permission` VALUES ('1', '19');
    INSERT INTO `t_role_permission` VALUES ('1', '20');
    INSERT INTO `t_role_permission` VALUES ('1', '21');
    INSERT INTO `t_role_permission` VALUES ('1', '22');
    INSERT INTO `t_role_permission` VALUES ('1', '23');
    INSERT INTO `t_role_permission` VALUES ('1', '24');
    INSERT INTO `t_role_permission` VALUES ('1', '25');
    INSERT INTO `t_role_permission` VALUES ('1', '26');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191

    1、Spring Security环境准备

    pom.xml中导入Spring Security的maven坐标,目前版本使用的是5.0.5.RELEASE,版本如果过高可能就会导致不同的报错

    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-web</artifactId>
      <version>${spring.security.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-config</artifactId>
      <version>${spring.security.version}</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    1.1、在health_backend工程的web.xml文件中配置用于整合Spring Security框架的过滤器DelegatingFilterProxy

    <!--委派过滤器,用于整合其他框架-->
    <filter>
      <!--整合spring security时,此过滤器的名称固定springSecurityFilterChain-->
      <filter-name>springSecurityFilterChain</filter-name>
      <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <!--注意区分放置的位置,有严格的先后顺序-->
    <filter-mapping>
      <filter-name>springSecurityFilterChain</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2、实现认证和授权

    1. 在health_backend工程中按照Spring Security框架要求提供SpringSecurityUserService,并且实现UserDetailsService接口

      package com.zcl.security;
      
      import com.alibaba.dubbo.config.annotation.Reference;
      import com.itheima.pojo.Permission;
      import com.itheima.pojo.Role;
      import com.itheima.pojo.User;
      import com.zcl.service.UserService;
      import org.springframework.security.core.GrantedAuthority;
      import org.springframework.security.core.authority.SimpleGrantedAuthority;
      import org.springframework.security.core.userdetails.UserDetails;
      import org.springframework.security.core.userdetails.UserDetailsService;
      import org.springframework.security.core.userdetails.UsernameNotFoundException;
      import org.springframework.stereotype.Component;
      
      import java.util.ArrayList;
      import java.util.List;
      import java.util.Set;
      
      /**
       * 项目名称:health_parent
       * 描述:SpringSecurity实现认证和授权
       *
       * @author zhong
       * @date 2022-06-24 12:09
       */
      @Component
      public class SpringSecurityUserService implements UserDetailsService {
      
          /**
           * 使用dubbo网络远程调用服务提供方查询用户数据
           */
          @Reference
          private UserService userService;
      
          /**
           * 根据用户名查询数据库获取用户信息
           * @param username
           * @return
           * @throws UsernameNotFoundException
           */
          @Override
          public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
              User user = userService.findByUsername(username);
              if(user == null) {return null;};
              List<GrantedAuthority> list = new ArrayList<>();
              // 动态为当前用户授权
              Set<Role> roles = user.getRoles();
              // 遍历角色集合,为用户授予角色
              for (Role role : roles) {
                  // 为用户授予角色
                  list.add(new SimpleGrantedAuthority(role.getKeyword()));
                  // 获取权限
                  Set<Permission> permissions = role.getPermissions();
                  // 遍历权限,为角色授权
                  for (Permission permission : permissions) {
                      list.add(new SimpleGrantedAuthority(permission.getKeyword()));
                  }
              }
      
              /*
               * 将密码交由框架比对
               * 参数一:账号
               * 参数二:查询数据库的密码,已加密的
               * 参数三:用户角色所具有的权限
               */
              org.springframework.security.core.userdetails.User UserSecurity = new org.springframework.security.core.userdetails.User(username,user.getPassword(),list);
              return UserSecurity;
          }
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
    2. 创建远程调用的UserService接口

      public interface UserService {
          /**
           * 根据登录名查询用户数据
           * @param username
           * @return
           */
          User findByUsername(String username);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    3. 创建接口实现类

      需要注入数据访问层来完成数据的查询,用户、角色、权限各自创建一个dao和映射文件

      package com.zcl.service.impl;
      
      import com.alibaba.dubbo.config.annotation.Service;
      import com.itheima.pojo.Permission;
      import com.itheima.pojo.Role;
      import com.itheima.pojo.User;
      import com.zcl.dao.PermissionDao;
      import com.zcl.dao.RoleDao;
      import com.zcl.dao.UserDao;
      import com.zcl.service.UserService;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.transaction.annotation.Transactional;
      
      import java.util.Set;
      
      /**
       * 项目名称:health_parent
       * 描述:用户服务实现类
       *
       * @author zhong
       * @date 2022-06-24 14:35
       */
      @Service(interfaceClass = UserService.class)
      @Transactional
      public class UserServiceImpl implements UserService {
      
          @Autowired
          private UserDao userDao;
      
          @Autowired
          private RoleDao roleDao;
      
          @Autowired
          private PermissionDao permissionDao;
      
          /**
           * 根据用户名称查询用户角色信息和关联的角色信息,同时需要查询角色关联的权限信息
           * @param username
           * @return
           */
          @Override
          public User findByUsername(String username) {
              // 1、查询用户基本信息,不包含用户角色信息
              User user = userDao.findByUsername(username);
              if(user == null){
                  return null;
              }
              // 2、根据用户查询的用户id查询角色信息
              Integer userId = user.getId();
              Set<Role> roles = roleDao.findByUserId(userId);
              // 3、根据角色来查询权限
              for (Role role : roles) {
                  Integer roleId = role.getId();
                  Set<Permission> permissions = permissionDao.findByRoleId(roleId);
                  // 让角色关联权限
                  role.setPermissions(permissions);
              }
              // 让用还关联角色
              user.setRoles(roles);
              return user;
          }
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
    4. 创建【用户、角色、权限】数据访问层接口

      注意:这三个接口都不是在同一个类中的,而是各自独立的接口类,不要写在一起

      public interface UserDao {
          User findByUsername(String username);
      }
      
      public interface RoleDao {
          Set<Role> findByUserId(Integer userId);
      }
      
      public interface PermissionDao {
          Set<Permission> findByRoleId(Integer roleId);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    5. 查询用户的Mapper映射文件查询数据

      映射文件创建在resources文件下,注意的是需要与dao接口的包一致

      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE mapper
              PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      <mapper namespace="com.zcl.dao.UserDao">
          <!--根据用户名称查询用户信息-->
          <select id="findByUsername" parameterType="string" resultType="com.itheima.pojo.User">
              select *
              from t_user
              where username = #{username}
          </select>
      </mapper>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
    6. 根据用户id查询角色信息Mapper映射文件查询

      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE mapper
              PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      <mapper namespace="com.zcl.dao.RoleDao">
          <!--根据用户id查询角色信息-->
          <select id="findByUserId" resultType="com.itheima.pojo.Role" parameterType="int">
              select r.*
              from t_role r,t_user_role ur
              where r.id = ur.role_id and ur.user_id = #{user_id}
          </select>
      </mapper>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
    7. 根据角色id查询角色权限Mapper映射文件

      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE mapper
              PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      <mapper namespace="com.zcl.dao.PermissionDao">
          <!--根据角色id查询权限-->
          <select id="findByRoleId" resultType="com.itheima.pojo.Permission" parameterType="int">
              select p.*
              from t_permission p,t_role_permission rp
              where p.id = rp.permission_id and rp.role_id = ${role_id}
          </select>
      </mapper>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
    8. 修改dubbo的批量扫描

      原因:默认配置的dubbo扫描的是Controller包下的,所以我们创建了一个新的包server用于存放权限实现类,而实现类刚好也是使用dubbo来远程调用接口查询数据库的,需要使用到dubbo就需要被扫描到

      <!--批量扫描-->
      <dubbo:annotation package="com.zcl" />
      
      • 1
      • 2
    9. 创建springSecurity.xml配置文件

      与上一篇的入门案例不同的是,SpringSecurityUserService认证提供者不需要在配置文件里面创建bean交给spring容器了,因为在类的上面已经使用@Component创建,在spring容器中已经有了,通过小写字母即可引用

      如果引用认证类报红就不需要管,影响不到程序,只是IDEA的检测问题

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:security="http://www.springframework.org/schema/security"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:mvc="http://www.springframework.org/schema/mvc"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
                                 http://www.springframework.org/schema/beans/spring-beans.xsd
                                http://www.springframework.org/schema/security
                                http://www.springframework.org/schema/security/spring-security.xsd
                                  http://www.springframework.org/schema/context
                                http://www.springframework.org/schema/context/spring-context.xsd
                                http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
      
          <!--配置哪些资源匿名可以访问的资源(不登录页可以访问)-->
          <security:http security="none" pattern="/login.html"></security:http>
          <security:http security="none" pattern="/css/**"></security:http>
          <security:http security="none" pattern="/js/**"></security:http>
          <security:http security="none" pattern="/img/**"></security:http>
          <security:http security="none" pattern="/plugins/**"></security:http>
      
          <!--
              http:用于定义相关权限控制
              auto-config:是否自动配置
                              设置为true时框架会提供默认的一些配置,例如提供默认的登录页面、登出处理等
                              设置为false时需要显示提供登录表单配置,否则会报错
              use-expressions:用于指定intercept-url中的access属性是否使用表达式
          -->
          <security:http auto-config="true" use-expressions="true">
              <security:headers>
                  <!--设置在页面可以通过iframe访问受保护的页面,默认为不允许访问-->
                  <security:frame-options policy="SAMEORIGIN"></security:frame-options>
              </security:headers>
              <!--
                  intercept-url:定义一个拦截规则
                  pattern:对哪些url进行权限控制
                  access:在请求对应的URL时需要什么权限,默认配置时它应该是一个以逗号分隔的角色列表,
      				  请求的用户只需拥有其中的一个角色就能成功访问对应的URL
              -->
              <!--只需要认证通过就可以访问-->
              <security:intercept-url pattern="/pages/**" access="isAuthenticated()"/>
      
              <!--如果我们要使用自己指定的页面作为登录页面,必须配置登录表单-->
              <security:form-login
                      login-page="/login.html"
                      username-parameter="username"
                      password-parameter="password"
                      login-processing-url="/login.do"
                      default-target-url="/pages/main.html"
                      authentication-failure-url="/login.html"/>
      
              <!--csrf:对应CsrfFilter过滤器
                  disabled:是否启用CsrfFilter过滤器,如果使用自定义登录页面需要关闭此项,否则登录操作会被禁用(403) -->
              <security:csrf disabled="true"/>
      
              <!--
                logout:退出登录
                logout-url:退出登录操作对应的请求路径
                logout-success-url:退出登录后的跳转页面
              -->
              <security:logout logout-url="/logout.do" logout-success-url="/login.html" invalidate-session="true"/>
          </security:http>
          <!--authentication-manager:认证管理器,用于处理认证操作-->
          <security:authentication-manager>
              <!--authentication-provider:认证提供者,执行具体的认证逻辑-->
              <security:authentication-provider user-service-ref="springSecurityUserService">
                  <!--引用密码加密处理bean-->
                  <security:password-encoder ref="passwordEncoder"/>
              </security:authentication-provider>
          </security:authentication-manager>
      
          <!--配置密码加密对象-->
          <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
      
          <!--开启注解方式权限控制-->
          <security:global-method-security pre-post-annotations="enabled"/>
      </beans>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77

      注意:<security:headers>的配置,如果没有配置这个对象就会访问不了嵌套的页面,哪怕是登录了也不行

      在springmvc.xml配置文件中引入springSecurity.xml配置文件

      <import resource="spring-security.xml"/>
      
      • 1
    10. 测试

      账号为:admin
      密码:admin
      admin加密后的形式为(存储到数据库):$2a$10$LPbhiutR34wKvjv3Qb8zBu7piw5hG3.IlQMAI3e/D1Y0DJ/mMSkYa
      
      • 1
      • 2
      • 3

    3、在控制器上实现注解鉴权

    注意:是在每一个控制器上面添加不同的权限,设置权限的只不能乱设置需要与数据库进行比对的才可以

    // 添加数据
    @PreAuthorize("hasAuthority('CHECKITEM_ADD')")
    
    // 查询数据
    @PreAuthorize("hasAuthority('CHECKITEM_QUERY')")
    
    // 删除数据
    @PreAuthorize("hasAuthority('CHECKITEM_DELETE')")
    
    // 修改数据
    @PreAuthorize("hasAuthority('CHECKITEM_EDIT')")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    "hasAuthority('CHECKITEM_ADD')"里面的值需要与数据库的权限值一致

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AdhpgYuN-1656071032135)(images/image-20220624171516474.png)]

    模拟没有权限删除数据:

    1、登录第二个账户:xiaoming

    2、账户中没有删除检查项,所以我们就已删除来测试

    3、点击删除的时候前端页面不会提示,查看后端控制器代码,发现被拦截了,如下报错:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hjmMk9uN-1656071032136)(images/image-20220624171823484.png)]

    4、切换回有删除权限的用户,删除查看效果

    3.1、完善前端页面访问权限不足提示

    在前端代码中编写一个方法被多个请求不成功函数所调用

    showMessage(r){
        if(r == 'Error: Request failed with status code 403'){
            //权限不足
            this.$message.error('无访问权限');
            return;
        }else{
            this.$message.error('未知错误');
            return;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在所有的请求方法上添加一个catch事件调用函数

    // 发送删除数据
    axios.get("/checkitem/delete.do?id="+row.id).then((res) => {
        // ... 回调方法
    }).catch ((r) => {
        this.showMessage(r);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    当用户操作时如果没有权限那么后端控制器就会将请求拦截下来,并在后端控制台打印拦截提示,同时前端页面回根据返回的报错类型做出无权限的提示信息,从而提高用户体验

    4、请求获取当前登录的用户名信息

    请求控制器获取用户名信息返回页面模型绑定给username用于展示

    // 发送ajax请求获取当前登录的用户名,展示到页面中
    axios.get("/user/getUsername.do").then((res) => {
        if(res.data.flag){
            this.username = res.data.data;
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    请求后端控制器编写

    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @RequestMapping("/getUsername")
        public Result getUsername(){
            // 当springsecurity完成认证后,会将当前用户信息保存到框架提供的上下文对象中
            User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            if (user != null) {
                System.out.println(user.getUsername());
                return new Result(true, MessageConstant.GET_USERNAME_SUCCESS,user.getUsername());
            }
            return new Result(false, MessageConstant.GET_USERNAME_FAIL);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    5、用户退出

    前端请求

    <el-dropdown-item divided>
      <span style="display:block;"><a href="/logout.do">退出</a></span>
    </el-dropdown-item>
    
    • 1
    • 2
    • 3

    后端配置文件中进行退出跳转设置

    <!--
      logout:退出登录
      logout-url:退出登录操作对应的请求路径
      logout-success-url:退出登录后的跳转页面
    -->
    <security:logout logout-url="/logout.do" 
                     logout-success-url="/login.html" invalidate-session="true"/>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    django-ORM
    2.物联网射频识别,RFID通信原理,RFID读写器与标签无线交互方式、数据反馈方式,RFID调制与解调、编码方式,不同RFID标签与读写器
    如何修改 Kafka 消息保留时长:经验总结
    【STM32】DMA数据转运(存储器到外设)
    宝塔面板使用docker+nginx+gunicorn部署Django项目实战教程
    Ansible的dict的key里包含圆点.
    对一门不是非常熟悉的语言是怎么面试的
    Multichain跨链无法到账,DApp真去中心化or伪去中心化?
    Zookeeper如何实现Leader选举
    odoo16原码安装后,psycopg2模块出错,应用除了网站其它都安装不了
  • 原文地址:https://blog.csdn.net/baidu_39378193/article/details/125451342