欢迎来真孝善网,为您提供真孝善正能量书籍故事!

高效角色权限管理系统:Springboot集成Mybatis与Shiro技术详解

时间:11-07 神话故事 提交错误

大家好,关于高效角色权限管理系统: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点了记住我的话关闭浏览器之后再次打开就不用再次登录

权限判断

在上面添加的测试数据中我们可以看到用户删除是没权限访问的

用户评论

虚伪了的真心

这个组合很经典啊,用来构建权限系统感觉很合适!

    有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位网友表示赞同!

【高效角色权限管理系统:Springboot集成Mybatis与Shiro技术详解】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活