大家好,关于高效角色权限管理系统:Springboot集成Mybatis与Shiro技术详解很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,还望关注下本站哦,希望对各位有所帮助!
1.创建springboot项目
主要介绍Mybatis、Shiro、Web、MySQL和
thymeleaf,因为页面实现的原因,我使用thymeleaf模板和lombok来简化实体类代码
这里还需要引入nekohtml,因为thymeleaf在验证HTML文件时会非常严格。例如,必须在末尾添加/。这里我们需要依赖nekohtmlorg.mybatis.spring.bootmybatis-spring-boot-starter1.3.1org.springframework.bootspring-boot -starter-thymeleafnet.sourceforge.nekohtmlnekohtml1.9.22org.springframework.bootspring-boot-starter-webmysqlmysql-连接器-javaruntimeorg.projectlomboklomboktrueorg.apache.shiroshiro-all1.4.0pomorg.springframework.bootspring-boot-starter-testtest
2.设计数据库表
010 -59000 image.png
不需要设置任何外键INSERT INTO `user_info` VALUES ("1", "admin", "d3c59d25033dbf980d29554025c23a75", "8d78869f470951332959580424d4bf4f", "1", "admin");
插入`sys_user_role` 值("1", "1");
插入`sys_role_permission` 值("1", "1");
插入`sys_role_permission` 值("2", "1");
插入`sys_role` 值("1", "1", "admin", "admin");
INSERT INTO `sys_role` VALUES ("2", "1", "VIP 会员", "vip");
INSERT INTO `sys_permission` VALUES ("1", "用户管理", "userInfo:view", "userInfo/userList");
INSERT INTO `sys_permission` VALUES ("2", "用户添加", "userInfo:add", "userInfo/userAdd");
INSERT INTO `sys_permission` VALUES ("3", "用户删除", "userInfo:del", "userInfo/userDel");
3.application.yml文件的配置
弹簧:
数据源:
url: jdbc:mysql: //localhost:3306/test1
username: 数据库用户名
password: 数据库密码
驱动程序类名: com.mysql.jdbc.Driver
百里香叶:
缓存:假
模式: LEGACYHTML5
mybatis:
类型别名-package: com.pjb.entity
mapper-locations: 类路径*:com.pjb.mapper/*.xml
4.实体类的编写
创建完表肯定要插入一些预备数据用lombok使实体类变得简单@Data
@AllArgsConstructor
@NoArgs构造函数
公共类用户信息{
Integer uid;//用户id
String 用户名;//账号
字符串名称;
字符串密码;
串盐;
字节状态;
/**
* 密码盐。
* @返回
*/
公共字符串getCredentialsSalt(){
返回this.用户名+this.salt;
}
}用户实体类@数据
@AllArgsConstructor
@NoArgs构造函数
公共类SysRole {
整数id;
String role;//角色识别程序用于判断,比如"admin",只有这个:
字符串描述; //角色描述
可用的私有布尔值=Boolean.FALSE; //可用吗?如果不可用,则不会添加到用户。
}角色实体类@数据
@AllArgsConstructor
@NoArgs构造函数
公共类系统权限{
Integer id;//主键。
字符串名称;//名称。
String url;//资源路径。
字符串权限; //权限字符串
}
5.mapper接口和xml文件
权限实体类@组件
公共接口UserInfoMapper {
//通过用户名查找用户角色信息
UserInfo findByUsername(@Param("用户名") 字符串用户名);
}用户mapper接口@组件
公共接口SysRoleMapper {
//通过用户名查找用户角色信息
ListfindRoleByUsername(@Param("用户名") 字符串用户名);
}角色mapper接口,一个用户对应多个角色@组件
公共接口SysPermissionMapper {
//根据角色ID查询角色对应的权限信息
ListfindPermissionByRoleId(@Param("roleId") Integer roleId);
}
对应的mapper.xml文件,这里最最最重要的就是SQL语句
UserInfoMapper.xml 这个查询很简单,没有使用多表查询
选择
用户信息.uid,
user_info.`name`,
用户信息.`密码`,
用户信息.salt,
用户信息.状态,
用户信息.用户名
从
用户信息
WHERE 用户名=#{用户名}权限mapper接口,一个角色对应多个权限下面都用到了多表查询,sql水平比较弱的可以用navicat去生成sql语句这里都没有用到外键选择
用户信息.uid,
user_info.`name`,
用户信息.`密码`,
用户信息.salt,
用户信息.状态,
user_info.用户名,
系统角色.id,
sys_role.可用,
sys_role.描述,
系统角色.角色
从
用户信息
右连接sys_user_role ON user_info.uid=sys_user_role.uid
左连接sys_role ON sys_user_role.role_id=sys_role.id
WHERE 用户名=#{用户名}SysRoleMapper.xml主要用到用户表,角色表和用户角色关联表选择
系统角色.id,
sys_role.可用,
sys_role.描述,
系统角色.角色,
sys_permission.`名称`,
sys_permission.权限,
sys_permission.url
从
(系统权限、系统角色)
右连接sys_role_permission ON sys_permission.id=sys_role_permission.permission_id
AND sys_role_permission.role_id=sys_role.id
WHERE sys_role.id=#{roleId}
6.简单的用户service层
公共接口UserInfoService {
/**通过用户名查找用户信息;*/
UserInfo findByUsername(字符串用户名);
}SysPermissionMapper.xml主要用到角色表,权限表和角色权限表@Service("UserInfoService")
公共类UserInfoServiceImpl 实现UserInfoService {
@Autowired
UserInfoMapper 用户信息映射器;
@覆盖
公共UserInfo findByUsername(字符串用户名) {
返回userInfoMapper.findByUsername(用户名);
}
}
7.自定义shiro配置
对应的service实现类MyShiroRealm 类,继承AuthorizingRealm 抽象类。
实现认证和授权两个方法public class MyShiroRealm extends AuthorizingRealm {
@Autowired
用户信息服务用户信息服务;
@Autowired
SysRoleMapper sysRoleMapper;
@Autowired
SysPermissionMapper sysPermissionMapper;
@覆盖
受保护的AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection 主体) {
System.out.println("权限配置--MyShiroRealm.doGetAuthorizationInfo()");
SimpleAuthorizationInfo 授权信息=new SimpleAuthorizationInfo();
UserInfo userInfo=(UserInfo)principal.getPrimaryPrincipal();
sysRoleMapper.findRoleByUsername(userInfo.getUsername()).stream().forEach(
系统角色-{
authorizationInfo.addRole(sysRole.getRole());
sysPermissionMapper.findPermissionByRoleId(sysRole.getId()).stream().forEach(
系统权限-{
authorizationInfo.addStringPermission(sysPermission.getPermission());
}
);
}
);
返回授权信息;
}
@覆盖
受保护的AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) 抛出AuthenticationException {
System.out.println("MyShiroRealm.doGetAuthenticationInfo()");
//获取用户输入的账号。
字符串用户名=(String)token.getPrincipal();
System.out.println(token.getCredentials());
//通过用户名从数据库中查找User对象。如果找到了,那就是没找到。
//实际项目中,这里可以根据实际情况进行缓存。如果没有的话,Shiro也有时间间隔机制,2分钟内不会重复执行这个方法。
UserInfo userInfo=userInfoService.findByUsername(用户名);
System.out.println("-----userInfo="+userInfo);
if(用户信息==空){
////当没有返回登录用户名对应的SimpleAuthenticationInfo对象时,会在LoginController中抛出UnknownAccountException异常。
返回空值;
}
SimpleAuthenticationInfo 身份验证信息=new SimpleAuthenticationInfo(
userInfo, //用户名
userInfo.getPassword(), //密码
ByteSource.Util.bytes(userInfo.getCredentialsSalt()),//salt=用户名+salt
getName() //领域名称
);
返回认证信息;
}
}Realm是一个Dao,通过它来验证用户身份和权限。只需要从我们的数据源中把用户和用户的角色权限信息取出来交给Shiro即可。authorizationInfo.addRole()是添加角色的方法这里我用java8函数式编程来代替原来的foreach循环。
ShiroConfig类已配置
authorizationInfo.addStringPermission()是添加权限的方法既然你使用的是Filter,那么一般可以猜测,过滤和权限验证都是通过URL规则进行的,所以我们需要定义一系列关于URL的规则和访问权限。
Apache Shiro 核心通过 Filter 来实现,就好像SpringMvc 通过DispachServlet 来主控制一样。需要声明为配置类(添加@Configuration),否则不会被拦截
@配置
公共类ShiroConfig {
@豆
公共ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
MapfilterChainDefinitionMap=new LinkedHashMap();
filterChainDefinitionMap.put("/logout", "logout");
filterChainDefinitionMap.put("/index", "用户");
filterChainDefinitionMap.put("/", "用户");
filterChainDefinitionMap.put("/favicon.ico", "anon");
filterChainDefinitionMap.put("/**", "authc");
//authc表示需要身份验证才能访问,有的比如anon表示不需要身份验证才能访问等
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
返回shiroFilterFactoryBean;
}
//SecurityManager是Shiro架构的核心,通过它链接Realm和用户(文档中称为Subject)。
@豆
公共安全管理器安全管理器(){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm()); //将Realm注入到SecurityManager中。
securityManager.setCacheManager(ehCacheManager()); //注入缓存对象。
securityManager.setRememberMeManager(cookieRememberMeManager()); //注入rememberMeManager;
返回安全管理器;
}
@豆
公共MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm=new MyShiroRealm();
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher()); //设置解密规则
返回我的ShiroRealm;
}
//因为我们的密码是加密的,所以如果想让Shiro验证用户的身份,就需要告诉它我们使用md5加密,并加密两次。同时我们也通过Realm中的SimpleAuthenticationInfo返回了加密时使用的salt。这样,Shiro就可以成功解密密码,并验证用户名和密码是否正确。
@豆
公共HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher=new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");//哈希算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(2);//哈希次数,如哈希两次,相当于md5(md5(""));
返回hashedCredentialsMatcher;
}
/**
* 启用shiro aop注释支持。
* 使用代理模式;所以需要启用代码支持;
* @param 安全管理器
*
@return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){ AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } @Bean public SimpleMappingExceptionResolver resolver() { SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver(); Properties properties = new Properties(); properties.setProperty("org.apache.shiro.authz.UnauthorizedException", "/403"); resolver.setExceptionMappings(properties); return resolver; } @Bean public EhCacheManager ehCacheManager() { System.out.println("ShiroConfiguration.getEhCacheManager()"); EhCacheManager ehCacheManager = new EhCacheManager(); ehCacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml"); return ehCacheManager; } //cookie对象; @Bean public SimpleCookie rememberMeCookie() { System.out.println("ShiroConfiguration.rememberMeCookie()"); //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); //simpleCookie.setMaxAge(259200); return simpleCookie; } //cookie管理对象; @Bean public CookieRememberMeManager cookieRememberMeManager() { System.out.println("ShiroConfiguration.rememberMeManager()"); CookieRememberMeManager manager = new CookieRememberMeManager(); manager.setCookie(rememberMeCookie()); return manager; } }①开启Shiro AOP注解支持 因为只有开启了AOP才执行doGetAuthorizationInfo(),也就权限拦截②我们开启了缓存 也就是授权只会进行一次,这样就避免了重复授权@Bean public EhCacheManager ehCacheManager() { System.out.println("ShiroConfiguration.getEhCacheManager()"); EhCacheManager ehCacheManager = new EhCacheManager(); ehCacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml"); return ehCacheManager; }然后将缓存对象注入到SecurityManager中就可以了③需要配置记住密码 正常登录后关闭浏览器,再打开浏览器输入http://localhost:8080/index,这时候就可以直接访问index页面,不需要再登录了。需要加入两个bean //cookie对象; @Bean public SimpleCookie rememberMeCookie() { System.out.println("ShiroConfiguration.rememberMeCookie()"); //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); //simpleCookie.setMaxAge(259200); return simpleCookie; } //cookie管理对象; @Bean public CookieRememberMeManager cookieRememberMeManager() { System.out.println("ShiroConfiguration.rememberMeManager()"); CookieRememberMeManager manager = new CookieRememberMeManager(); manager.setCookie(rememberMeCookie()); return manager; }同样将其注入到SecurityManager中就可以了 在ShiroFilterFactoryBean中添加记住我过滤器user,添加user过滤器的资源在记住我或认证之后就可以直接访问了。 filterChainDefinitionMap.put("/index", "user"); filterChainDefinitionMap.put("/", "user");在login.html页面添加记住我单选框 记住我以上三点我认为AOP是必须加的,不然怎样进行权限认证呢,其他两点自己选择,不需要的可以把相关代码去掉加入controller
HomeController@Controller public class HomeController { @RequestMapping({"/","/index"}) public String index(){ return"/index"; } // 这里如果不写method参数的话,默认支持所有请求,如果想缩小请求范围,还是要添加method来支持get, post等等某个请求。 @RequestMapping("/login") public String login(HttpServletRequest request, Mapmap) throws Exception { System.out.println("HomeController.login"); // 登录失败从request中获取shiro处理的异常信息。 // shiroLoginFailure:就是shiro异常类的全类名. Object exception = request.getAttribute("shiroLoginFailure"); String msg = ""; if (exception != null) { if (UnknownAccountException.class.isInstance(exception)) { System.out.println("账户不存在"); msg = "账户不存在或密码不正确"; } else if (IncorrectCredentialsException.class.isInstance(exception)) { System.out.println("密码不正确"); msg = "账户不存在或密码不正确"; } else { System.out.println("其他异常"); msg = "其他异常"; } } map.put("msg", msg); // 此方法不处理登录成功,由shiro进行处理. return "login"; } @RequestMapping("/403") public String unauthorizedRole(){ System.out.println("------没有权限-------"); return "403"; } }没有权限的操作将会跳转到403页面,没登录的操作将会强制跳转到登录界面UserInfoController@Controller @RequestMapping("/userInfo") public class UserInfoController { /** * 用户查询. * @return */ @RequestMapping("/userList") @RequiresPermissions("userInfo:view")//权限管理; public String userInfo(){ return "userInfo"; } /** * 用户添加; * @return */ @RequestMapping("/userAdd") @RequiresPermissions("userInfo:add")//权限管理; public String userInfoAdd(){ return "userInfoAdd"; } /** * 用户删除; * @return */ @RequestMapping("/userDel") @RequiresPermissions("userInfo:del")//权限管理; public String userDel(){ return "userInfoDel"; } }权限操作的接口@RequiresPermissions:当前Subject需要拥有某些特定的权限时,才能执行被该注解标注的方法。如果当前Subject不具有这样的权限,则方法不会被执行。测试
打开浏览器如果未登录的话可以定义到http://localhost:8080/loginimage.png点了记住我的话关闭浏览器之后再次打开就不用再次登录权限判断
在上面添加的测试数据中我们可以看到用户删除是没权限访问的【高效角色权限管理系统:Springboot集成Mybatis与Shiro技术详解】相关文章:
2.米颠拜石
3.王羲之临池学书
8.郑板桥轶事十则
用户评论
这个组合很经典啊,用来构建权限系统感觉很合适!
有14位网友表示赞同!
确实,SpringBoot快速搭建框架,Mybatis操作数据库方便,Shiro做权限控制非常成熟。
有5位网友表示赞同!
学习Spring Boot的时候正好遇到了权限管理的需求,看来这个标题的内容很有用!
有5位网友表示赞同!
看了下官网好像都有很多关于这三个技术栈的教程,打算去试试。
有15位网友表示赞同!
我现在项目中用的都是这些技术的组合,好用!
有6位网友表示赞同!
感觉做个角色权限系统要学习很多的知识啊。
有11位网友表示赞同!
我比较喜欢Shiro,它很强大可以用来实现很多复杂的逻辑控制。
有8位网友表示赞同!
Mybatis的sql语句写起来确实比较清晰易读。
有20位网友表示赞同!
想试下Spring Boot的快速开发能力,这个帖子也许能给我一些启发。
有19位网友表示赞同!
最近在网上搜了很多关于SpringBoot+Shiro的文章,感觉学习起来还是有一定的门槛。
有7位网友表示赞同!
角色管理系统挺重要的,用户体验会更好。
有10位网友表示赞同!
这个三者搭配,是不是可以实现各种精细化的权限控制呢?
有17位网友表示赞同!
对于新手来说,这三个技术肯定比较容易入门学习。
有20位网友表示赞同!
我想要在一个平台上整合多重模块,看这篇文章会不会有用的提示?
有20位网友表示赞同!
感觉这个标题包含的信息非常具体实用!
有7位网友表示赞同!
想了解一下Shiro的配置方式,这方面的资料比较少吗?
有5位网友表示赞同!
学习一个完整的权限系统,应该从基础概念开始理解吧。
有14位网友表示赞同!