项目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配置配置权限就要做好数据库权限表的维护等