建表:一个用户可以有多个角色,一个角色有多个访问权限,有普通请求URL权限,按钮权限,菜单权限(图标,父级菜单)
# 用户表
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`(
`uid` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(50) DEFAULT NULL COMMENT '用户名称',
`fullname` varchar(50) DEFAULT NULL COMMENT '用户昵称',
`password` varchar(255) DEFAULT NULL COMMENT '密码',
`salt` varchar(255) DEFAULT NULL COMMENT '密码盐',
`status` int(1) NOT NULL COMMENT '状态:0可用;1冻结',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO `sys_user` (`uid`,`username`,`fullname`,`password`,`salt`,`status`) VALUES ('1', 'root', '超级管理员', '02f7f19c004b7f3369f29b34f868fb4a', '6a6ad5eadcd06d22cab18e31b4d0cdab', 0);
# 角色表
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`rid` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`rname` varchar(50) DEFAULT NULL COMMENT '角色名称',
`description` varchar(255) DEFAULT NULL COMMENT '角色描述',
`status` int(1) NOT NULL COMMENT '状态:0有效;1无效',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`rid`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
# 权限表
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
`pid` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`pname` varchar(255) DEFAULT NULL COMMENT '权限名称',
`description` varchar(255) DEFAULT NULL COMMENT '权限描述',
`url` varchar(255) DEFAULT NULL COMMENT '权限访问路径',
`ptype` int(1) NOT NULL COMMENT '类型:0普通权限,1按钮权限,2菜单权限',
`parent_pid` int(11) COMMENT '上级菜单',
`innc` varchar(255) DEFAULT NULL COMMENT '图标',
`status` int(1) NOT NULL COMMENT '状态:0有效;1无效',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
# 用户角色关系表
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role`(
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`uid` varchar(20) NOT NULL COMMENT '用户id',
`rid` varchar(20) NOT NULL COMMENT '角色id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
# 角色权限关系表
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`rid` varchar(20) NOT NULL COMMENT '角色id',
`pid` varchar(20) NOT NULL COMMENT '权限id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
package com.oo.core.dao;
import java.util.List;
import org.apache.ibatis.annotations.Select;
import com.oo.comm.MyMapper;
import com.oo.core.entity.SysPermission;
public interface SysPermissionMapper extends MyMapper<SysPermission>{
@Select("select * from sys_permission")
List<SysPermission> selectAll();
@Select("select * from sys_permission as p inner join sys_role_permission as rp on p.pid=rp.pid where rp.rid = #{rid}")
List<SysPermission> selectByRid(Long rid);
}
package com.oo.core.dao;
import org.apache.ibatis.annotations.Many;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.mapping.FetchType;
import com.oo.core.entity.SysUser;
public interface SysUserMapper{
@Select("select uid,username,password,fullname,status,salt,create_time as createTime,update_time as updateTime from sys_user where username = #{username}")
@Results({
@Result(property="uid",column="uid"),
@Result(property="sysRoleList",column="uid",many=@Many(select="com.oo.core.dao.SysRoleMapper.selectByUid",fetchType=FetchType.LAZY))//在关联查询时,利用延迟加载,先加载主信息。使用关联信息时再去加载关联信息
})
public SysUser selectByUsername(String username);
}
mybatis:
mapper-locations: classpath:mapper/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #MyBatis 输出SQL日志
cache-enabled: true
一个用户多个角色,一个角色多个权限,MyBatis对象一对多关系映射,延迟加载
权限配置
package com.oo.config.shiro;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.oo.core.entity.SysPermission;
import com.oo.core.service.impl.SysPermissionService;
/**
* 用户权限配置类
* @author LU http://blog.csdn.net/phone13144830339
* @date 2018年11月10日
*/
@Configuration
public class ShiroConfig {
@Autowired
SysPermissionService sysPermissionService;
/**
* 配置过滤器
* @param securityManager
* @return
*/
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
//定义shiroFactoryBean
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
//设置securityManager 安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
/*
Shiro内置的FilterChain,一个URL可以配置多个Filter,使用逗号分隔。当配置多个过滤器时,全部验证通过才视为通过。部分过滤器可以指定参数,如:perms,roles
anon org.apache.shiro.web.filter.authc.AnonymousFilter
authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter
authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
port org.apache.shiro.web.filter.authz.PortFilter
rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
ssl org.apache.shiro.web.filter.authz.SslFilter
user org.apache.shiro.web.filter.authc.UserFilter
*/
//进行顺序过滤器配置 LinkedHashMap是有序的
Map<String,String> filterChainMap = new LinkedHashMap<String,String>();
//资源文件访问配置,anon匿名访问、authc用户认证、roles角色、perms权限
filterChainMap.put("/css/**","anon");
filterChainMap.put("/js/**","anon");
filterChainMap.put("/img/**","anon");
filterChainMap.put("/login", "anon");
filterChainMap.put("/logout","logout");
//动态权限配置
List<SysPermission> sysPermissionList = sysPermissionService.selectAll();
for(SysPermission sysPermission:sysPermissionList) {
filterChainMap.put(sysPermission.getUrl(), sysPermission.getPname());
}
filterChainMap.put("/**","authc");//其它的,要authc:用户认证
shiroFilterFactoryBean.setLoginUrl("/login.html");//设置用户进行认证跳转的页面
shiroFilterFactoryBean.setSuccessUrl("/index.html");//设置用户认证成功跳转的页面
shiroFilterFactoryBean.setUnauthorizedUrl("/403.html");//设置用户没有权限跳转的页面
//设置shiroFilterFactoryBean的FilterChainDefinitionMap
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
return shiroFilterFactoryBean;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//设置自定义realm
securityManager.setRealm(myShiroRealm());
return securityManager;
}
/**
* 身份认证realm;(这个需要自己写,账号密码校验;用户权限赋予等)
* @return
*/
@Bean
public MyShiroRealm myShiroRealm(){
MyShiroRealm myShiroRealm = new MyShiroRealm();
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myShiroRealm;
}
/**
* 凭证匹配器
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(1);//散列的次数,比如散列两次,相当于 md5(md5(""));
return hashedCredentialsMatcher;
}
}
自定义Relam,用户认证,用户授权(访问需要权限的url时,进行回调)
package com.oo.config.shiro;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
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 com.oo.core.entity.SysRole;
import com.oo.core.entity.SysUser;
import com.oo.core.service.impl.SysUserService;
/**
* 自定义realm实现认证
*/
public class MyShiroRealm extends AuthorizingRealm {
@Autowired
SysUserService sysUserService;
/**
* 认证信息(身份验证)
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
//获取用户的输入的账号Subject login登入时, Token中传递的用户名称参数,UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());//用户名称,用户密吗
String username = token.getUsername();
SysUser user = sysUserService.selectSysUserByUsername(username);
//账号不存在
if (null == user) {
throw new UnknownAccountException();
}
//账号被冻结
if (user.getStatus()==1) {
throw new LockedAccountException();
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(),ByteSource.Util.bytes(user.getSalt()), getName());
return authenticationInfo;
}
/**
* 用户 授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
SysUser sysUser = (SysUser)principals.getPrimaryPrincipal();
sysUser=sysUserService.selectSysUserByUsername(sysUser.getUsername());
System.out.println(sysUser);
for(SysRole role:sysUser.getSysRoleList()){
authorizationInfo.addRole(role.getRname());
/*for(SysPermission p:role.getPermissions()){
authorizationInfo.addStringPermission(p.getPermission());
}*/
}
authorizationInfo.addStringPermission("add:user");
return authorizationInfo;
}
}
登入访问控制
package com.oo.core.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import com.oo.core.entity.SysUser;
@Controller
public class LoginController {
Logger logger = LoggerFactory.getLogger(LoginController.class);
@PostMapping("/login")
String login(SysUser user) {
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());//用户名称,用户密吗
String error = null;
Subject currentUser = SecurityUtils.getSubject();
try {
currentUser.login(token);
} catch (UnknownAccountException e) {
error = "账号错误";
e.printStackTrace();
} catch (IncorrectCredentialsException e) {
error = "密码错误";
e.printStackTrace();
} catch (LockedAccountException e) {
error ="账号冻结";
e.printStackTrace();
} catch (AuthenticationException e) {
error = "其他问题";
e.printStackTrace();
}
if(error==null) {
return "redirect:index.html";
} else {
logger.info("登入失败!"+"["+error+"]");
return "redirect:login.html";
}
}
}