項目git網址:https://github.com/David-BIQI/manage.git(項目使用比較新的springboot2.0 還有jdk8 )
參照的代碼規范:https://github.com/xwjie/PLMCodeTemplate.git (這個是一套能夠落地的代碼規范,跟着風哥學習很多)
shiro的數據庫設計
用戶表、角色表、權限表、用戶與角色中間表、角色與權限中間表
drop table if exists permission; drop table if exists role; drop table if exists role_to_permission; drop table if exists user_to_role; /*==============================================================*/ /* Table: permission */ /*==============================================================*/ create table permission ( id int not null auto_increment, name varchar(50) comment '權限名稱', url varchar(100) not null comment '請求路徑', permission varchar(150) not null comment '角色編碼', status tinyint(1) default 1, created datetime default CURRENT_TIMESTAMP, createdby int, updated datetime default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, updatedby int default 0, remark varchar(50) default '', primary key (id) ); alter table permission comment '權限表'; /*==============================================================*/ /* Table: role */ /*==============================================================*/ create table role ( id int not null auto_increment, role_name varchar(100) not null comment '角色名稱', role_code varchar(150) not null comment '角色編碼', status tinyint(1) default 1, created datetime default CURRENT_TIMESTAMP, createdby int, updated datetime default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, updatedby int, remark varchar(50) default '', primary key (id) ); alter table role comment '角色表'; /*==============================================================*/ /* Table: role_to_permission */ /*==============================================================*/ create table role_to_permission ( id int not null auto_increment, permission_id varchar(100) not null comment '權限id', role_id varchar(150) not null comment '角色id', status tinyint(1) default 1, created datetime default CURRENT_TIMESTAMP, createdby int, updated datetime default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, updatedby int, primary key (id) ); alter table role_to_permission comment '角色與權限表'; /*==============================================================*/ /* Table: user_to_role */ /*==============================================================*/ create table user_to_role ( id int not null auto_increment, user_id varchar(100) not null, role_id varchar(150) not null, status tinyint(1) default 1, created datetime default CURRENT_TIMESTAMP, createdby int, updated datetime default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, updatedby int, primary key (id) ); alter table user_to_role comment '用戶角色表';
shiro結合springboot
@Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) { System.out.println("ShiroConfiguration.shirFilter()"); ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); //攔截器. Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>(); // 配置不會被攔截的鏈接 順序判斷 filterChainDefinitionMap.put("/static/**", "anon"); //配置退出 過濾器,其中的具體的退出代碼Shiro已經替我們實現了 filterChainDefinitionMap.put("/logout", "logout"); //<!-- 過濾鏈定義,從上向下順序執行,一般將/**放在最為下邊 -->:這是一個坑呢,一不小心代碼就不好使了; //<!-- authc:所有url都必須認證通過才可以訪問; anon:所有url都都可以匿名訪問--> filterChainDefinitionMap.put("/**", "authc"); // 如果不設置默認會自動尋找Web工程根目錄下的"/login.jsp"頁面 shiroFilterFactoryBean.setLoginUrl("/login"); // 登錄成功后要跳轉的鏈接 shiroFilterFactoryBean.setSuccessUrl("/main"); //未授權界面; shiroFilterFactoryBean.setUnauthorizedUrl("/403"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } /** * 憑證匹配器 * (由於我們的密碼校驗交給Shiro的SimpleAuthenticationInfo進行處理了 * ) * @return */ @Bean public HashedCredentialsMatcher hashedCredentialsMatcher(){ HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:這里使用MD5算法; // hashedCredentialsMatcher.setHashIterations(2);//散列的次數,比如散列兩次,相當於 md5(md5("")); return hashedCredentialsMatcher; } @Bean public UserRealm myShiroRealm(){ UserRealm myShiroRealm = new UserRealm(); myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher()); return myShiroRealm; } @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myShiroRealm()); return securityManager; } /** * 開啟shiro aop注解支持. * 使用代理方式;所以需要開啟代碼支持; * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){ AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } @Bean(name="simpleMappingExceptionResolver") public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() { SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver(); Properties mappings = new Properties(); mappings.setProperty("DatabaseException", "databaseError");//數據庫異常處理 mappings.setProperty("UnauthorizedException","403"); r.setExceptionMappings(mappings); // None by default r.setDefaultErrorView("error"); // No default r.setExceptionAttribute("ex"); // Default is "exception" //r.setWarnLogCategory("example.MvcLogger"); // No default return r; }
real的校驗
@Slf4j public class UserRealm extends AuthorizingRealm { //注入角色權限等表 @Autowired private PermissionDao permissionDao; @Autowired private RoleDao roleDao; @Autowired private RoleToPermissionDao roleToPermissionDao; @Autowired private UserDao userDao; @Autowired private UserToRoleDao userToRoleDao; /** * 授權 * @param principals * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); User userInfo = (User)principals.getPrimaryPrincipal(); UserToRole userToRole = new UserToRole(); userToRole.setUserId(userInfo.getId()); List<UserToRole> roleList = userToRoleDao.select(userToRole); //獲取role表和權限表-->設置到realm中去 List<Role> roles = new ArrayList<>(roleList.size()); //List<Role> roles = roleDao.selectAll(); roleList.forEach(item->{ roles.add(roleDao.selectByPrimaryKey(item.getRoleId())); }); roles.forEach(item->{ authorizationInfo.addRole(item.getRoleName()); RoleToPermission roleToPermission = new RoleToPermission(); roleToPermission.setStatus(BaseConstant.STATUS.YES); roleToPermission.setRoleId(item.getId()); List<RoleToPermission> select = roleToPermissionDao.select(roleToPermission); for (RoleToPermission itemRoleToPermission : select) { Permission permission = permissionDao.selectByPrimaryKey(itemRoleToPermission.getPermissionId()); authorizationInfo.addStringPermission(permission.getPermission()); } }); System.out.println(authorizationInfo.toString()); return authorizationInfo; } /** * @param token * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("MyShiroRealm.doGetAuthenticationInfo()"); //獲取用戶的輸入的賬號. String username = (String)token.getPrincipal(); System.out.println(token.getCredentials()); //通過username從數據庫中查找 User對象,如果找到,沒找到. User user = new User(); user.setName(username); User userInfo = userDao.selectOne(user); System.out.println("----->>userInfo="+userInfo); if(userInfo == null){ return null; } SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo( userInfo, //用戶名 userInfo.getPassword(), //密碼 ByteSource.Util.bytes("123"),//salt=username+salt getName() //realm name ); return authenticationInfo; } }
最后shiro通過注解實現
shiro實現實現攔截器的功能,自身集成session的管理等,通過注解權限好上手,通過jdbc配置配置權限就要做好數據庫權限表的維護等