項目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配置配置權限就要做好數據庫權限表的維護等
