1. 程式人生 > >RBAC權限控制

RBAC權限控制

stl tex 調用 root eal nco fas main ive

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\r\n‘, ‘2018-11-13‘, ‘2018-11-13‘, ‘1‘, ‘1‘, ‘1‘, ‘1‘);
INSERT INTO `sys_user` VALUES (‘2‘, ‘userAdd‘, ‘小余‘, ‘15a013bcac0c50049356b322e955035e\r\n‘, ‘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進行動態配置修改的啦~~

RBAC權限控制