ssm+shrio+jsp 升级为springboot之权限整理

由于用到了权限框架,所以架构重构还是有点注意项的
思路 :
把权限 相关的xml所实例化的bean 由代码是去实现下
AuthorizingRealm–》securityManager—》ShiroFilterFactoryBean
每一个去继承实现下,当然比如如果你需要认证的时候加密加盐
就可能需要注入相关子类
以Realm为例,现在我要用SHA256加密
可能在实现AuthorizingRealm的时候去实现 HashedCredentialsMatcher

package com.ect.bigdata.esync.account.security;

import com.ect.bigdata.esync.common.config.GlobalConfig;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.springframework.stereotype.Component;

import java.util.concurrent.atomic.AtomicInteger;

@Component
public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {

    private Ehcache passwordRetryEhcache;

    public RetryLimitHashedCredentialsMatcher() {
        CacheManager cacheManager = CacheManager.newInstance(CacheManager.class.getClassLoader().getResource("ehcache.xml"));

        passwordRetryEhcache = cacheManager.getCache("passwordRetryEhcache");

    }

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        String username = (String) token.getPrincipal();
        //2.判断缓存中是否包含含有此用户名的Element
        Element element = passwordRetryEhcache.get(username);
        if(element!=null) {
            element.setTimeToIdle(GlobalConfig.getLoginRetryLimitExpired());
        }
        //3.如果没有 ,就创建包含该用户名的Element并添加到缓存
        if (element == null) {
            element = new Element(username, new AtomicInteger(0));
            passwordRetryEhcache.put(element);
        }
        //4.如果有 就通过该Element获取AutomicInteger
        AtomicInteger atomicInteger = (AtomicInteger) element.getObjectValue();

        if (GlobalConfig.isLoginRetryTimesLimit()) {
            //5.如果AutomicInteger的incrementAndGet大于5 就抛异常
            if (atomicInteger.incrementAndGet() > GlobalConfig.getLoginRetryTimes()) {
                throw new ExcessiveAttemptsException();
            }
        }
        //6.如果小于5 就调用父类的doCredentialsMatch方法进行密码验证
        boolean matchs = super.doCredentialsMatch(token, info);
        //7.如果验证通过,就将该username从缓存中清除
        if (matchs) {
            passwordRetryEhcache.remove(username);
        }

        return matchs;
    }
}
@Configuration
public class ShiroConfig {
    @Bean(name = "myRealm")
    public SecurityDatabaseRealm myAuthRealm(RetryLimitHashedCredentialsMatcher retryLimitHashedCredentialsMatcher) {
        SecurityDatabaseRealm myRealm = new SecurityDatabaseRealm();
        retryLimitHashedCredentialsMatcher.setHashAlgorithmName("SHA-256");
        retryLimitHashedCredentialsMatcher.setHashIterations(2);
        retryLimitHashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        myRealm.setCredentialsMatcher(retryLimitHashedCredentialsMatcher);
        return myRealm;
    }
<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="es">
    <diskStore path="java.io.tmpdir"/>
    <!-- 登录记录缓存 锁定3分钟 -->
    <cache name="passwordRetryEhcache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
</ehcache>

仔细看下代码和我们平时写的赋值操作是一样的

如果之间你直接封装好可以直接使用@Component
实例化下就可以了,然后在shiroConig中注入,废话不多说贴图
好了 以上解释仁者见仁,智者见智吧
步骤一:肯定先整认证的AuthorizingRealm

package com.ect.bigdata.esync.account.security;

import com.ect.bigdata.esync.account.AccountService;
import com.ect.bigdata.esync.account.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Set;

/**
 * 实现 Shiro Realm ,用于获取认证信息与权限信息
 * 
 */
@Slf4j
@Component
public class SecurityDatabaseRealm extends AuthorizingRealm {

    @Autowired
    private AccountService accountService;


    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authToken;
        String username = token.getUsername();

        if (username == null) {
            throw new UnknownAccountException("Null usernames are not allowed by this realm.");
        }

        User user = accountService.findByUsername(username);

        if (user == null) {
            String msg = String.format("No account found for user [%s].", username);
            log.warn(msg);
//            throw new UnknownAccountException(msg);
            return null;
        }

//        char[] password = token.getPassword();
//        Set<String> userRoles = new HashSet<>();
//        Set<String> rolePermissions = new HashSet<>();
//        userRoles = accountService.getUserRoles(username);
//        rolePermissions = accountService.getRolePermissions();

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());
//        int salt = new Random().nextInt(2 << 30 -1);
        String salt = user.getSalt();
        log.debug("salt: {}", salt);
        info.setCredentialsSalt(ByteSource.Util.bytes(salt));
        return info;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        if (principals == null) {
            throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
        }

        String username = (String) getAvailablePrincipal(principals);
        Set<String> roleNames = null;
        Set<String> permissions = null;
        try {
            roleNames = accountService.getRoleNamesForUser(username);

            permissions = accountService.getPermissions(roleNames);

        } catch (Exception e) {
            log.error("Exception getting authorization info!", e);
        }

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
        info.setStringPermissions(permissions);

        return info;
    }

}

登录次数校验,以及实现何种加密方式

package com.ect.bigdata.esync.account.security;

import com.ect.bigdata.esync.common.config.GlobalConfig;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.springframework.stereotype.Component;

import java.util.concurrent.atomic.AtomicInteger;

@Component
public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {

    private Ehcache passwordRetryEhcache;

    public RetryLimitHashedCredentialsMatcher() {
        CacheManager cacheManager = CacheManager.newInstance(CacheManager.class.getClassLoader().getResource("ehcache.xml"));

        passwordRetryEhcache = cacheManager.getCache("passwordRetryEhcache");

    }

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        String username = (String) token.getPrincipal();
        //2.判断缓存中是否包含含有此用户名的Element
        Element element = passwordRetryEhcache.get(username);
        if(element!=null) {
            element.setTimeToIdle(GlobalConfig.getLoginRetryLimitExpired());
        }
        //3.如果没有 ,就创建包含该用户名的Element并添加到缓存
        if (element == null) {
            element = new Element(username, new AtomicInteger(0));
            passwordRetryEhcache.put(element);
        }
        //4.如果有 就通过该Element获取AutomicInteger
        AtomicInteger atomicInteger = (AtomicInteger) element.getObjectValue();

        if (GlobalConfig.isLoginRetryTimesLimit()) {
            //5.如果AutomicInteger的incrementAndGet大于5 就抛异常
            if (atomicInteger.incrementAndGet() > GlobalConfig.getLoginRetryTimes()) {
                throw new ExcessiveAttemptsException();
            }
        }
        //6.如果小于5 就调用父类的doCredentialsMatch方法进行密码验证
        boolean matchs = super.doCredentialsMatch(token, info);
        //7.如果验证通过,就将该username从缓存中清除
        if (matchs) {
            passwordRetryEhcache.remove(username);
        }

        return matchs;
    }
}

重点来了,以下是如何引用核心配置

package com.ect.bigdata.esync.account.security;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {
    @Bean(name = "myRealm")
    public SecurityDatabaseRealm myAuthRealm(RetryLimitHashedCredentialsMatcher retryLimitHashedCredentialsMatcher) {
        SecurityDatabaseRealm myRealm = new SecurityDatabaseRealm();
        retryLimitHashedCredentialsMatcher.setHashAlgorithmName("SHA-256");
        retryLimitHashedCredentialsMatcher.setHashIterations(2);
        retryLimitHashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        myRealm.setCredentialsMatcher(retryLimitHashedCredentialsMatcher);
        return myRealm;
    }

    @Bean(name = "securityManager")
    public SecurityManager securityManager(@Qualifier("myRealm") SecurityDatabaseRealm myRealm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(myRealm);
        return manager;
    }

    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String,String> filterMap = new LinkedHashMap<String, String>();
        filterMap.put("/login/**","anon");
        filterMap.put("/sys/version","anon");
        filterMap.put("/merge/test","anon");
        filterMap.put("/","authc");
        filterMap.put("/monitor/**","authc");
        filterMap.put("/profile/**","authc");
        filterMap.put("/logout/**","authc");
        filterMap.put("/merge/**","authc");
        filterMap.put("/logout/**","roles[admin]");
        filterMap.put("/dist/**","anon");
        filterMap.put("/bower_components/**","anon");
        filterMap.put("//plugins/**","anon");
        filterMap.put("/css/**","anon");
        filterMap.put("/js/**","anon");
        filterMap.put("/img/**","anon");
        //修改跳转的登陆页面
        shiroFilterFactoryBean.setLoginUrl("/login");
        //转跳至未授权页面【友好提示】
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
        //跳转至成功页面
        shiroFilterFactoryBean.setSuccessUrl("/monitor");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactoryBean;
    }
}

控制器使用:

package com.ect.bigdata.esync.account;

import com.ect.bigdata.esync.account.entity.Role;
import com.ect.bigdata.esync.account.entity.User;
import com.ect.bigdata.esync.common.config.GlobalConfig;
import com.ect.bigdata.esync.common.util.LoginAesUtil;
import com.ect.bigdata.esync.common.util.PasswordEncryptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 账户相关的控制器
 * @author 
 */
@Slf4j
@Controller
public class AccountController {

    private static final String LOGIN_VIEW = "login";
    private static final String CHANGE_CREDENTIAL_VIEW = "change-password";
    private static final String USER_PROFILE_VIEW = "profile";
    private static final String UNAUTHORIZED_VIEW = "unauthorized";

    /**
     * 使用Bootstrap的组件来展示 SpringMVC 的 Flash Attributes
     */
    private static final String HTML_MESSAGE =
            "<div id=\"flash-message\" class=\"alert alert-danger\" role=\"alert\">\n" +
            "    <strong>%s</strong>\n" +
            "</div>";

    /**
     * 成功展示
     */
    private static final String HTML_SUCCESS =
            "<div id=\"flash-message\" class=\"alert alert-success\" role=\"alert\">\n" +
                    "    <strong>%s</strong>\n" +
                    "</div>";

    @Autowired
    private AccountService accountService;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String viewIndex() {
        log.debug("Access to index view.");
        return "redirect:/monitor";
    }

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String viewLogin() {
        log.debug("Access to login view.");
        return LOGIN_VIEW;
    }

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public String submitLoginView(@RequestParam("username") String username, @RequestParam("password") String password,
                           Model model, RedirectAttributes redirectAttributes) throws Exception {
        log.info("Login with username [{}] and password.", username);
        final String FLASH_ALERT_MESSAGE = "errorLoginFlashMessage";
        String validationFailureMessage="";
        if(GlobalConfig.isLoginRetryTimesLimit()) {
             validationFailureMessage = "账号或密码错误,您仅有" + GlobalConfig.getLoginRetryTimes() + "次尝试机会!";
        }else {
             validationFailureMessage = "账号或密码错误";
        }
        if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
            log.warn("Login with blank username or password, just ignore!");
            model.addAttribute(FLASH_ALERT_MESSAGE, String.format(HTML_MESSAGE, "账号或密码不能为空!"));
            return LOGIN_VIEW;
        }

        // 前端加密密码还原
        password = LoginAesUtil.aesDecrypt(password);

        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        log.info("token -> {}", token);

        try {
            log.info("SecurityUtils.getSubject() -> {}", SecurityUtils.getSubject());
            SecurityUtils.getSubject().login(token);

            // 将用户及角色信息放入会话中
            User user = accountService.findByUsername(username);
            Set<String> roleNames = accountService.getRoleNamesForUser(username);
            List<String> roleNameList = new ArrayList<>(roleNames);
            List<Role> roleList = accountService.findRolesBy(roleNameList);
            user.setRoleList(roleList);

            List<String> roleDescriptionList = new ArrayList<>();
            for (Role role : roleList) {
                String roleDescription = role.getDescription();
                roleDescriptionList.add(roleDescription);
            }

            SecurityUtils.getSubject().getSession().setAttribute("username", username);
            SecurityUtils.getSubject().getSession().setAttribute("user", user);
            SecurityUtils.getSubject().getSession().setAttribute("roleNamesOfUser", roleNameList);
            SecurityUtils.getSubject().getSession().setAttribute("roleDescriptions", roleDescriptionList);
        } catch (ExcessiveAttemptsException e) {
            log.error("Login attempt more than 5 times, account enabled and disabled, see the configuration file for details", e);
            model.addAttribute(FLASH_ALERT_MESSAGE, String.format(HTML_MESSAGE, "登录认证失败超过5次,账号锁定" + ((int) (GlobalConfig.getLoginRetryLimitExpired() / 60)) + "分钟"));
            return LOGIN_VIEW;
        } catch (UnknownAccountException uae) {
            log.warn("Authenticating failed due to UnknownAccountException!");
            model.addAttribute(FLASH_ALERT_MESSAGE, String.format(HTML_MESSAGE, validationFailureMessage));

            return LOGIN_VIEW;
        } catch (IncorrectCredentialsException ice) {
            log.warn("Authenticating failed due to IncorrectCredentialsException!");
            model.addAttribute(FLASH_ALERT_MESSAGE, String.format(HTML_MESSAGE, validationFailureMessage));

            return LOGIN_VIEW;
        } catch (AuthenticationException e) {
            log.error("Exception authenticating!", e);
            model.addAttribute(FLASH_ALERT_MESSAGE, String.format(HTML_MESSAGE, "登录认证失败,账号或密码错误!"));

            return LOGIN_VIEW;
        }

        // 重定向时,不能使用 Model 来传值,因为 Model 中的一切都会在重定向经过客户端浏览器时丢失!
        redirectAttributes.addFlashAttribute("message", "The user is logged in successfully!");

        log.info("Login success, redirect monitor page!");
        return "redirect:/monitor/";
    }

    @RequestMapping(value = "/logout", method = RequestMethod.GET)
    public String logout(@RequestParam("username") String username,
                         Model model) throws Exception {
        SecurityUtils.getSubject().logout();
        log.info("SecurityUtils.getSubject().getSession().getAttributeKeys() -> {}", SecurityUtils.getSubject().getSession().getAttributeKeys());
        log.info("SecurityUtils.getSubject().getSession().getAttribute(username) -> {}", SecurityUtils.getSubject().getSession().getAttribute("username"));
        log.info("SecurityUtils.getSubject().getPrincipal() -> {}", SecurityUtils.getSubject().getPrincipal());


        log.info("Current user [{}] logout successfully!", username);
        return "redirect:/login";
    }

    @RequestMapping(value = "/change-password", method = RequestMethod.GET)
    public String viewChangePassword() throws Exception {
        log.info("Access to CHANGE_CREDENTIAL_VIEW.");
        return CHANGE_CREDENTIAL_VIEW;
    }

    @RequestMapping(value = "/change-password", method = RequestMethod.POST)
    public String submitChangePasswordView(@RequestParam("username") String username,
                                           @RequestParam("oldPassword") String oldPassword,
                                           @RequestParam("newPassword") String newPassword,
                                           Model model, RedirectAttributes redirectAttributes) throws Exception {
        log.info("Submitting CHANGE_CREDENTIAL_VIEW with username [{}].", username);
        final String FLASH_ALERT_MESSAGE = "flashAlertMessage";

        if (StringUtils.isBlank(username) || StringUtils.isBlank(oldPassword) || StringUtils.isBlank(newPassword) ) {
            log.warn("Ignore when inputting blank account/oldPassword/newPassword!");
            model.addAttribute(FLASH_ALERT_MESSAGE, String.format(HTML_MESSAGE, "账号、原密码或新密码不能为空!"));
            return CHANGE_CREDENTIAL_VIEW;
        }
        User user = accountService.findByUsername(username);
        // 前端加密密码还原
        oldPassword = LoginAesUtil.aesDecrypt(oldPassword);
        newPassword = LoginAesUtil.aesDecrypt(newPassword);

        if (newPassword.equals(oldPassword)) {
            log.warn("Old password and new password cannot be equal!");
            model.addAttribute(FLASH_ALERT_MESSAGE, String.format(HTML_MESSAGE, "新密码不能和原密码相同!"));
            return CHANGE_CREDENTIAL_VIEW;
        }
        if (newPassword.length() < 8 || newPassword.length() > 10) {
            log.warn("New password length should be 8~10!");
            model.addAttribute(FLASH_ALERT_MESSAGE, String.format(HTML_MESSAGE, "新密码长度应该为8~10位!"));
            return CHANGE_CREDENTIAL_VIEW;
        }
        // 对旧密码进行加密 用于对比数据库密码
        oldPassword = new PasswordEncryptor().encrypt(oldPassword,user.getSalt());
        if (user == null || !oldPassword.equals(user.getPassword())) {
            log.warn("Invalid account or incorrect old password!");
            model.addAttribute(FLASH_ALERT_MESSAGE, String.format(HTML_MESSAGE, "账号或原密码错误!"));
            return CHANGE_CREDENTIAL_VIEW;
        }
        // 对新密码进行加密
        newPassword = new PasswordEncryptor().encrypt(newPassword,user.getSalt());

        user.setPassword(newPassword);
        try {
            accountService.saveUser(user);
        } catch (Exception e) {
            String errorMsg = String.format("Exception changing password for user [%s]!", username);
            log.error(errorMsg, e);
            throw new Exception(errorMsg);
        }
        log.info("Change password for user [{}] successfully.", username);


        redirectAttributes.addFlashAttribute("successFlashMessage", String.format(HTML_SUCCESS, "密码更新成功"));
        return "redirect:login";
    }

    @RequestMapping(value = "/profile", method = RequestMethod.GET)
    public String viewUserProfile() throws Exception {
        log.info("Access to USER_PROFILE_VIEW.");
        // TODO
        // 展示当前用户信息:用户名、角色列表、简介(包含姓名、部门、团队、邮箱、电话等)
        return USER_PROFILE_VIEW;
    }

    @RequestMapping(value = "/profile2", method = RequestMethod.GET)
    public String viewUserProfile2() throws Exception {
        log.info("Access to USER_PROFILE_VIEW.");
        return "profile2";
    }

    @RequestMapping(value = "/profile", method = RequestMethod.POST)
    public String submitUserProfileView() throws Exception {
        log.info("Submitting USER_PROFILE_VIEW.");
        // TODO
        return USER_PROFILE_VIEW;
    }

    @RequestMapping(value = "/unauthorized", method = RequestMethod.GET)
    public String viewUnauthorized() throws Exception {
        log.info("Access to UNAUTHORIZED_VIEW.");
        // TODO
        return UNAUTHORIZED_VIEW;
    }
}

数据库建表:

/*
SQLyog 企业版 - MySQL GUI v8.14 
MySQL - 5.5.59-MariaDB : Database - tmpdb
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*Table structure for table `cdep_permission` */

DROP TABLE IF EXISTS `cdep_permission`;

CREATE TABLE `cdep_permission` (
  `id` bigint(20) NOT NULL,
  `permission` varchar(50) NOT NULL COMMENT '权限名',
  `resource` varchar(1000) DEFAULT NULL COMMENT '权限资源值',
  `create_by` varchar(15) DEFAULT NULL COMMENT '创建者',
  `update_by` varchar(15) DEFAULT NULL COMMENT '修改者',
  `create_at` datetime DEFAULT NULL COMMENT '创建时间',
  `update_at` datetime DEFAULT NULL COMMENT '更新时间',
  `valid` int(11) DEFAULT '1' COMMENT '是否有效 (1有效, 0无效),用于逻辑删除',
  `version` int(11) DEFAULT NULL COMMENT '版本,用于乐观锁',
  PRIMARY KEY (`id`),
  UNIQUE KEY `permission` (`permission`),
  KEY `ix_cp_permission` (`permission`),
  KEY `ix_cp_update_at` (`update_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CDEP权限表';

/*Table structure for table `cdep_role` */

DROP TABLE IF EXISTS `cdep_role`;

CREATE TABLE `cdep_role` (
  `id` bigint(20) NOT NULL,
  `role_name` varchar(50) NOT NULL COMMENT '角色名',
  `description` varchar(255) DEFAULT NULL COMMENT '描述',
  `create_by` varchar(15) DEFAULT NULL COMMENT '创建者',
  `update_by` varchar(15) DEFAULT NULL COMMENT '修改者',
  `create_at` datetime DEFAULT NULL COMMENT '创建时间',
  `update_at` datetime DEFAULT NULL COMMENT '更新时间',
  `valid` int(11) DEFAULT '1' COMMENT '是否有效 (1有效, 0无效),用于逻辑删除',
  `version` int(11) DEFAULT NULL COMMENT '版本,用于乐观锁',
  PRIMARY KEY (`id`),
  UNIQUE KEY `role_name` (`role_name`),
  KEY `ix_cr_role_name` (`role_name`),
  KEY `ix_cr_update_at` (`update_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CDEP角色表';

/*Table structure for table `cdep_role_permission` */

DROP TABLE IF EXISTS `cdep_role_permission`;

CREATE TABLE `cdep_role_permission` (
  `id` bigint(20) NOT NULL,
  `role_id` varchar(32) DEFAULT NULL,
  `permission_id` varchar(32) DEFAULT NULL,
  `create_by` varchar(15) DEFAULT NULL COMMENT '创建者',
  `update_by` varchar(15) DEFAULT NULL COMMENT '修改者',
  `create_at` datetime DEFAULT NULL COMMENT '创建时间',
  `update_at` datetime DEFAULT NULL COMMENT '更新时间',
  `valid` int(11) DEFAULT '1' COMMENT '是否有效 (1有效, 0无效),用于逻辑删除',
  `version` int(11) DEFAULT NULL COMMENT '版本,用于乐观锁',
  PRIMARY KEY (`id`),
  KEY `ix_crp_role_id` (`role_id`),
  KEY `ix_crp_permission_id` (`permission_id`),
  KEY `ix_crp_update_at` (`update_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CDEP角色权限关联表';

/*Table structure for table `cdep_user` */

DROP TABLE IF EXISTS `cdep_user`;

CREATE TABLE `cdep_user` (
  `id` bigint(20) NOT NULL,
  `username` varchar(50) NOT NULL COMMENT '用户名',
  `password` varchar(100) DEFAULT NULL COMMENT '密码',
  `salt` varchar(100) DEFAULT NULL COMMENT '盐值,用于密码加密',
  `enabled` int(11) DEFAULT '1' COMMENT '是否启用 (1启用, 0禁用)',
  `locked` int(11) DEFAULT '0' COMMENT '是否锁定 (1是, 0否)',
  `expired` int(11) DEFAULT '0' COMMENT '是否过期 (1是, 0否)',
  `description` varchar(255) DEFAULT NULL COMMENT '描述',
  `create_by` varchar(15) DEFAULT NULL COMMENT '创建者',
  `update_by` varchar(15) DEFAULT NULL COMMENT '修改者',
  `create_at` datetime DEFAULT NULL COMMENT '创建时间',
  `update_at` datetime DEFAULT NULL COMMENT '更新时间',
  `valid` int(11) DEFAULT '1' COMMENT '是否有效 (1有效, 0无效),用于逻辑删除',
  `version` int(11) DEFAULT NULL COMMENT '版本,用于乐观锁',
  PRIMARY KEY (`id`),
  KEY `ix_cu_username` (`username`),
  KEY `ix_cu_update_at` (`update_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CDEP用户表';

/*Table structure for table `cdep_user_role` */

DROP TABLE IF EXISTS `cdep_user_role`;

CREATE TABLE `cdep_user_role` (
  `id` bigint(20) NOT NULL,
  `user_id` varchar(32) DEFAULT NULL,
  `role_id` varchar(32) DEFAULT NULL,
  `create_by` varchar(15) DEFAULT NULL COMMENT '创建者',
  `update_by` varchar(15) DEFAULT NULL COMMENT '修改者',
  `create_at` datetime DEFAULT NULL COMMENT '创建时间',
  `update_at` datetime DEFAULT NULL COMMENT '更新时间',
  `valid` int(11) DEFAULT '1' COMMENT '是否有效 (1有效, 0无效),用于逻辑删除',
  `version` int(11) DEFAULT NULL COMMENT '版本,用于乐观锁',
  PRIMARY KEY (`id`),
  KEY `ix_cur_user_id` (`user_id`),
  KEY `ix_cur_role_id` (`role_id`),
  KEY `ix_cur_update_at` (`update_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CDEP用户角色关联表';

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值