• RBAC权限控制


    1、什么是RBAC权限模型rity
    2、RBAC权限模型表设计
    3、整合Mybatis数据库
    4、UserDetailsService
    5、动态查询数据库登陆
    6、动态权限角色拦截

    什么是RBAC权限模型r

    基于角色的权限访问控制(Role-Based Access Control)作为传统访问控制(自主访问,强制访问)的有前景的代替受到广泛的关注。在RBAC中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。在一个组织中,角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色。角色可依新的需求和系统的合并而赋予新的权限,而权限也可根据需要而从某角色中回收。角色与角色的关系可以建立起来以囊括更广泛的客观情况。
    百度百科:https://baike.baidu.com/item/RBAC/1328788?fr=aladdin

    微服务系统中,管理平台也是有分布式的,比如会员管理,订单管理,支付管理等

    最终通过SSO将公司颞部所有管理进行整合。 比如用户同一登录 www.toov5.com 进行管理

     
    将权限的设置信息 不要写死 通过表去进行动态的配置 动态的维护   整合Mybatis就OK了

     通过表的动态配置

    参考前面的写死的配置

      

     数据库环境:

    SET FOREIGN_KEY_CHECKS=0;
    
    -- ----------------------------
    -- Table structure for sys_permission
    -- ----------------------------
    DROP TABLE IF EXISTS `sys_permission`;
    CREATE TABLE `sys_permission` (
      `id` int(10) NOT NULL,
      `permName` varchar(50) DEFAULT NULL,
      `permTag` varchar(50) DEFAULT NULL,
      `url` varchar(255) DEFAULT NULL COMMENT '请求url',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of sys_permission
    -- ----------------------------
    INSERT INTO `sys_permission` VALUES ('1', '查询订单', 'showOrder', '/showOrder');
    INSERT INTO `sys_permission` VALUES ('2', '添加订单', 'addOrder', '/addOrder');
    INSERT INTO `sys_permission` VALUES ('3', '修改订单', 'updateOrder', '/updateOrder');
    INSERT INTO `sys_permission` VALUES ('4', '删除订单', 'deleteOrder', '/deleteOrder');
    
    -- ----------------------------
    -- Table structure for sys_role
    -- ----------------------------
    DROP TABLE IF EXISTS `sys_role`;
    CREATE TABLE `sys_role` (
      `id` int(10) NOT NULL,
      `roleName` varchar(50) DEFAULT NULL,
      `roleDesc` varchar(50) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of sys_role
    -- ----------------------------
    INSERT INTO `sys_role` VALUES ('1', 'admin', '管理员');
    INSERT INTO `sys_role` VALUES ('2', 'add_user', '添加管理员');
    
    -- ----------------------------
    -- Table structure for sys_role_permission
    -- ----------------------------
    DROP TABLE IF EXISTS `sys_role_permission`;
    CREATE TABLE `sys_role_permission` (
      `role_id` int(10) DEFAULT NULL,
      `perm_id` int(10) DEFAULT NULL,
      KEY `FK_Reference_3` (`role_id`),
      KEY `FK_Reference_4` (`perm_id`),
      CONSTRAINT `FK_Reference_4` FOREIGN KEY (`perm_id`) REFERENCES `sys_permission` (`id`),
      CONSTRAINT `FK_Reference_3` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of sys_role_permission
    -- ----------------------------
    INSERT INTO `sys_role_permission` VALUES ('1', '1');
    INSERT INTO `sys_role_permission` VALUES ('1', '2');
    INSERT INTO `sys_role_permission` VALUES ('1', '3');
    INSERT INTO `sys_role_permission` VALUES ('1', '4');
    INSERT INTO `sys_role_permission` VALUES ('2', '1');
    INSERT INTO `sys_role_permission` VALUES ('2', '2');
    
    -- ----------------------------
    -- Table structure for sys_user
    -- ----------------------------
    DROP TABLE IF EXISTS `sys_user`;
    CREATE TABLE `sys_user` (
      `id` int(10) NOT NULL,
      `username` varchar(50) DEFAULT NULL,
      `realname` varchar(50) DEFAULT NULL,
      `password` varchar(50) DEFAULT NULL,
      `createDate` date DEFAULT NULL,
      `lastLoginTime` date DEFAULT NULL,
      `enabled` int(5) DEFAULT NULL,
      `accountNonExpired` int(5) DEFAULT NULL,
      `accountNonLocked` int(5) DEFAULT NULL,
      `credentialsNonExpired` int(5) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of sys_user
    -- ----------------------------
    INSERT INTO `sys_user` VALUES ('1', 'admin', '张三', '15a013bcac0c50049356b322e955035e
    ', '2018-11-13', '2018-11-13', '1', '1', '1', '1');
    INSERT INTO `sys_user` VALUES ('2', 'userAdd', '小余', '15a013bcac0c50049356b322e955035e
    ', '2018-11-13', '2018-11-13', '1', '1', '1', '1');
    
    -- ----------------------------
    -- Table structure for sys_user_role
    -- ----------------------------
    DROP TABLE IF EXISTS `sys_user_role`;
    CREATE TABLE `sys_user_role` (
      `user_id` int(10) DEFAULT NULL,
      `role_id` int(10) DEFAULT NULL,
      KEY `FK_Reference_1` (`user_id`),
      KEY `FK_Reference_2` (`role_id`),
      CONSTRAINT `FK_Reference_2` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`),
      CONSTRAINT `FK_Reference_1` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of sys_user_role
    -- ----------------------------
    INSERT INTO `sys_user_role` VALUES ('1', '1');
    INSERT INTO `sys_user_role` VALUES ('2', '2');

    对密码需要加密 md5加密    

    对传入到后台的数据进行比对:

    对于加密后的处理逻辑:

    maven:

            <!-->spring-boot 整合security -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
            <!-- springboot 整合mybatis框架 -->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.2</version>
            </dependency>
            <!-- alibaba的druid数据库连接池 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.9</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>

     用户登录时候 会去各个表中查询出信息

     包括权限信息

     通过查询出来的信息给配置文件赋值,动态赋值。

     管理者可以通过管理这些表去进行权限的管理。

     对于User的bean字段需要严格按照规范去写,框架已经定义了接口,需要去实现:

      

    // 用户信息表
    @Data
    public class User implements UserDetails {
       //框架地层查询时候 必须依赖的字段 实现这个接口 规范了名称
        private Integer id;
        private String username;
        private String realname;
        private String password;
        private Date createDate;
        private Date lastLoginTime;
        private boolean enabled;
        private boolean accountNonExpired;
        private boolean accountNonLocked;
        private boolean credentialsNonExpired;
        // 用户所有权限
        private List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    
        public Collection<? extends GrantedAuthority> getAuthorities() {  //一个用户可能多个权限 所以用了集合去处理存储
            return authorities;
        }
    
    }

    对于数据库的查询:Mapper层

      

    import java.util.List;
    
    import org.apache.ibatis.annotations.Select;
    
    import com.mayikt.entity.Permission;
    
    public interface PermissionMapper {
    
        // 查询苏所有权限
        @Select(" select * from sys_permission ")
        List<Permission> findAllPermission();
    
    }

      

    import java.util.List;
    
    import org.apache.ibatis.annotations.Param;
    import org.apache.ibatis.annotations.Select;
    
    import com.mayikt.entity.Permission;
    import com.mayikt.entity.User;
    
    public interface UserMapper {
        // 查询用户信息
        @Select(" select * from sys_user where username = #{userName}")
        User findByUsername(@Param("userName") String userName);
    
        // 查询用户的权限
        @Select(" select permission.* from sys_user user" + " inner join sys_user_role user_role"
                + " on user.id = user_role.user_id inner join "
                + "sys_role_permission role_permission on user_role.role_id = role_permission.role_id "
                + " inner join sys_permission permission on role_permission.perm_id = permission.id where user.username = #{userName};")
        List<Permission> findPermissionByUsername(@Param("userName") String userName);
    }

    登录时候会首先执行的Java类:

     先查询出User信息

    使用UserDetailsService实现动态查询数据库验证账号

    import java.util.ArrayList;
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    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.Service;
    
    import com.mayikt.entity.Permission;
    import com.mayikt.entity.User;
    import com.mayikt.mapper.UserMapper;
    
    // 设置动态用户信息
    @Service
    public class MyUserDetailsService implements UserDetailsService {
        @Autowired
        private UserMapper userMapper;
    
        @Override   //用户登录时候会调用这个方法 
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    
            // 1.根据用户名称查询数据用户信息
            User user = userMapper.findByUsername(username);
            // 2.底层会根据数据库查询用户信息,判断密码是否正确   开发者需要做的就是查询就OK了
            // 3. 给用户设置权限     查询出来 然后赋值就OK了
            List<Permission> listPermission = userMapper.findPermissionByUsername(username);
            System.out.println("username:" + username + ",对应权限:" + listPermission.toString());
            if (listPermission != null && listPermission.size() > 0) {
                // 定义用户权限
                List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
                for (Permission permission : listPermission) {
                    authorities.add(new SimpleGrantedAuthority(permission.getPermTag()));
                }
                user.setAuthorities(authorities);
            }
            return user;
        }
    
    }

    进行权限的校验 设置:

    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
    import org.springframework.security.crypto.password.NoOpPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.stereotype.Component;
    
    import com.mayikt.entity.Permission;
    import com.mayikt.handler.MyAuthenticationFailureHandler;
    import com.mayikt.handler.MyAuthenticationSuccessHandler;
    import com.mayikt.mapper.PermissionMapper;
    import com.mayikt.security.MyUserDetailsService;
    import com.mayikt.utils.MD5Util;
    
    // Security 配置
    @Component
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        private MyAuthenticationFailureHandler failureHandler;
        @Autowired
        private MyAuthenticationSuccessHandler successHandler;
        @Autowired
        private MyUserDetailsService myUserDetailsService;
        @Autowired
        private PermissionMapper permissionMapper;
    
        // 配置认证用户信息和权限
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            // // 添加admin账号
            // auth.inMemoryAuthentication().withUser("admin").password("123456").
            // authorities("showOrder","addOrder","updateOrder","deleteOrder");
            // // 添加userAdd账号
            // auth.inMemoryAuthentication().withUser("userAdd").password("123456").authorities("showOrder","addOrder");
            // 如果想实现动态账号与数据库关联 在该地方改为查询数据库
            auth.userDetailsService(myUserDetailsService).passwordEncoder(new PasswordEncoder() {
    
                // 加密的密码与数据库密码进行比对CharSequence rawPassword 表单字段 encodedPassword
                // 数据库加密字段
                public boolean matches(CharSequence rawPassword, String encodedPassword) {
                    System.out.println("rawPassword:" + rawPassword + ",encodedPassword:" + encodedPassword);
                    // 返回true 表示认证成功 返回fasle 认证失败
                    Boolean reslt = MD5Util.encode((String) rawPassword).equals(encodedPassword);
                    System.out.println("result结果:"+reslt);
                    return reslt;
                }
    
                // 对表单密码进行加密
                public String encode(CharSequence rawPassword) {
                    System.out.println("rawPassword:" + rawPassword);
                    return MD5Util.encode((String) rawPassword);
                }
            });
        }
    
        // 配置拦截请求资源    进行动态请求资源
        protected void configure(HttpSecurity http) throws Exception {
            ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests = http
                    .authorizeRequests();
            // 1.读取数据库权限列表
            List<Permission> listPermission = permissionMapper.findAllPermission();
            for (Permission permission : listPermission) {
                // 设置权限
                authorizeRequests.antMatchers(permission.getUrl()).hasAnyAuthority(permission.getPermTag());
            }
            authorizeRequests.antMatchers("/login").permitAll().antMatchers("/**").fullyAuthenticated().and().formLogin()
                    .loginPage("/login").successHandler(successHandler).and().csrf().disable();
    
        }
    
        @Bean
        public static NoOpPasswordEncoder passwordEncoder() {
            return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
        }
    
    }

    yml:

    # 配置freemarker
    spring:
      freemarker:
        # 设置模板后缀名
        suffix: .ftl
        # 设置文档类型
        content-type: text/html
        # 设置页面编码格式
        charset: UTF-8
        # 设置页面缓存
        cache: false
        # 设置ftl文件路径
        template-loader-path:
          - classpath:/templates
      # 设置静态文件路径,js,css等
      mvc:
        static-path-pattern: /static/**
    ####整合数据库层    
      datasource:
        name: test
        url: jdbc:mysql://127.0.0.1:3306/rbac_db
        username: root
        password: root
        # druid 连接池
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        

    加密工具:

    import java.security.MessageDigest;
    
    public class MD5Util {
    
        // 加盐
        private static final String SALT = "toov5";
    
        public static String encode(String password) {
            password = password + SALT;
            MessageDigest md5 = null;
            try {
                md5 = MessageDigest.getInstance("MD5");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            char[] charArray = password.toCharArray();
            byte[] byteArray = new byte[charArray.length];
    
            for (int i = 0; i < charArray.length; i++)
                byteArray[i] = (byte) charArray[i];
            byte[] md5Bytes = md5.digest(byteArray);
            StringBuffer hexValue = new StringBuffer();
            for (int i = 0; i < md5Bytes.length; i++) {
                int val = ((int) md5Bytes[i]) & 0xff;
                if (val < 16) {
                    hexValue.append("0");
                }
    
                hexValue.append(Integer.toHexString(val));
            }
            return hexValue.toString();
        }
    
        public static void main(String[] args) {
            System.out.println(MD5Util.encode("123456"));
    
        }
    }

    启动类:

    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @MapperScan("com.toov5.mapper")
    @SpringBootApplication
    public class AppSecurity {
    
        public static void main(String[] args) {
            SpringApplication.run(AppSecurity.class, args);
            // Security 两种模式 fromLogin 表单提交认证模式 httpBasic 浏览器与服务器做认证授权
        }
    
    }

    这样就成为了 根据SQL进行动态配置修改的啦~~

  • 相关阅读:
    jquery笔记
    linux的日常经常使用的命令
    IDEA设置类注解和方法注解(详解)
    java读取项目或包下面的属性文件方法
    枚举类的使用
    将一个浮点数转化为人民币大写字符串
    简单五子棋实现
    crontab 设置服务器定期执行备份工作
    linux创建日期文件名
    代码层读写分离实现
  • 原文地址:https://www.cnblogs.com/toov5/p/10325520.html
Copyright © 2020-2023  润新知