Shiro-SpringBoot (一)
前不久负责项目中刚好也使用了Shiro做权限控制,趁着空闲期想把之前做的整理一下。在日常项目开发中,权限认证是不可少的模块。比较常用的有Spring Security,或是轻量级的Apache Shiro。相对来说Shiro提供了认证、授权、加密、会话管理、与Web集成、缓存等。这些都是日常会用到的,而且Shiro的API比较简洁,学习成本相对低。接下来将整理一下在SpringBoot中如何集成Shiro:
- RBAC介绍
- SpringBoot集成Shiro和配置
- Shiro的登录和认证
- 当前不足点
(一) RBAC介绍
**RBAC(Role-Based Access Control )**基于角色访问控制,在权限设计上用户是基于角色进行权限认证,而角色又是和资源相关联的。这样在设计和管理上简化了权限的操作,它们都是层级依赖,更方便我们的管理。如此一来,数据库表设计可以如下图:
(二) SpringBoot集成Shiro和配置
1、导入Shiro依赖
在pom.xml中加入以下依赖
<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.2.5</version>
</dependency>
2、配置Shiro
在配置之前,首先了解一下Shiro中主要功能,并看看它们主要是做什么的。
- Subject 安全视角下与软件交互的实体(用户,第三方服务等等)
- Authenticator 用户登录时进行账户的认证
- Authorizer 用户登录时进行账户的权限资源认证
- Realms每当执行认证或授权时,shiro会从程序配置的一个或多个Realm中查询
新建JAVA类ShiroRealm用于继承Shiro的AuthorizingRealm抽象类,并复写doGetAuthenticationInfo和doGetAuthorizationInfo用于账户和权限的认证。
public class ShiroRealm extends AuthorizingRealm {@Autowiredprivate UserService userService;@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;String userName = token.getUsername();String password = new String((char[])token.getCredentials());//这里可以自行查询数据库进行验证if(userName != "zhangshan" && password != DigestUtils.md5Hex("123456")) {throw new UnknownAccountException ("未知的账户认证失败");}SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userName, //用户名DigestUtils.md5Hex("123456"), //密码getName() //realm name);//存入session//SecurityUtils.getSubject().getSession().setAttribute("user", user);return authenticationInfo;}@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {String useCode = (String) principalCollection.getPrimaryPrincipal();SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();Map<String,Object> userAuthorityInfoMap = userService.getUserAuthorityInfo(useCode);//这里可以从数据库进行查询List<String> roles = new ArrayList<String>();List<String> perms = mew ArrayList<String>();roles.add("管理员");perms.add("查看用户模块");simpleAuthorizationInfo.addRoles(roles);simpleAuthorizationInfo.addStringPermissions(perms);return simpleAuthorizationInfo;}}
在SpringBoot中配置Shiro,配置URL过滤规则
@Configuration
public class ShiroConfiguration {/*** 负责org.apache.shiro.util.Initializable类型bean的生命周期的,初始化和销毁。*/@Bean(name = "lifecycleBeanPostProcessor")public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}/*** shiro密码认证配置,使用MD5 HEX16进制*/@Bean(name = "hashedCredentialsMatcher")public HashedCredentialsMatcher hashedCredentialsMatcher() {HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();credentialsMatcher.setHashAlgorithmName("MD5");credentialsMatcher.setHashIterations(1);//散列的次数,相当于md5("");credentialsMatcher.setStoredCredentialsHexEncoded(true);//采用HEX16进制编码return credentialsMatcher;}/*** ShiroRealm,需要自己实现自定义的认证类,继承自AuthorizingRealm,负责用户的认证和权限的处理*/@Bean(name = "shiroRealm")@DependsOn("lifecycleBeanPostProcessor")public ShiroRealm shiroRealm() {ShiroRealm realm = new ShiroRealm();//realm.setCacheManager(ehCacheManager());return realm;}/*** EhCacheManager,缓存管理,用户登陆成功后,把用户信息和权限信息缓存起来,* 然后每次用户请求时,放入用户的session中,如果不设置这个bean,每个请求都会查询一次数据库。*/
// @Bean(name = "ehCacheManager")
// @DependsOn("lifecycleBeanPostProcessor")
// public EhCacheManager ehCacheManager() {// EhCacheManager ehcacheManager = new EhCacheManager();
// //ehcacheManager.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml");
// return ehcacheManager;
// }/*** SecurityManager权限管理,主营管理登陆,登出,权限,session的处理*/@Bean(name = "securityManager")public DefaultWebSecurityManager securityManager() {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();securityManager.setRealm(shiroRealm());//securityManager.setCacheManager(ehCacheManager());return securityManager;}/*** ShiroFilterFactoryBean配置URL过滤链规则*/@Bean(name = "shiroFilter")public ShiroFilterFactoryBean shiroFilterFactoryBean() {ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();shiroFilterFactoryBean.setSecurityManager(securityManager);shiroFilterFactoryBean.setLoginUrl("/login");shiroFilterFactoryBean.setSuccessUrl("/index");shiroFilterFactoryBean.setUnauthorizedUrl("/pages/403");Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();//Shiro拦截URL规则filterChainDefinitionMap.put("/logout", "logout");filterChainDefinitionMap.put("/js/**", "anon");filterChainDefinitionMap.put("/css/**", "anon");filterChainDefinitionMap.put("/login", "anon");filterChainDefinitionMap.put("/403", "anon");filterChainDefinitionMap.put("/userInfo/**", "authc,perms[查看用户模块]");filterChainDefinitionMap.put("/messageInfo/**", "authc,roles[管理员]");filterChainDefinitionMap.put("/**", "authc");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return shiroFilterFactoryBean;}/*** 由Advisor决定对哪些类的方法进行AOP代理。*/@Bean@ConditionalOnMissingBeanpublic DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();defaultAAP.setProxyTargetClass(true);return defaultAAP;}/*** shiro里实现的Advisor类,内部使用AopAllianceAnnotationsAuthorizingMethodInterceptor来拦截用以下注解的方法。*/@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {AuthorizationAttributeSourceAdvisor aASA = new AuthorizationAttributeSourceAdvisor();aASA.setSecurityManager(securityManager());return aASA;}}
(三) Shiro的登录和认证
新建LoginController进行登录验证Shiro。在subject.login(token)这行代码执行的时候,Shiro会回调我们上面实现的ShiroRealm进行账户认证和权限认证。
@RequestMapping("/login")
@Controller
public class LoginController {private static Logger logger = LoggerFactory.getLogger(LoginController.class);@RequestMapping(method = RequestMethod.GET)@ResponseBodypublic String loginPage(){return "login";}@RequestMapping(value = "/check",method = RequestMethod.POST)@ResponseBodypublic String login(@RequestParam("userName") String userName, @RequestParam("passWord") String passWord){Subject subject = SecurityUtils.getSubject();UsernamePasswordToken token = new UsernamePasswordToken(userCode, DigestUtils.md5Hex(passWord));try {subject.login(token);} catch (Exception e) {logger.error("用户用户名和密码..验证未通过");return "redirect:/login";}// catch (UnknownAccountException e) {// logger.error("未知的账户认证失败);// } catch (DisabledAccountException e) {// logger.error("账户已经被禁用,认证失败");// }return "/index";}}
(四) 当前不足点
到这里Shiro已经可以进行登录验证,在配置中也可以对指定的URL拦截,并通过角色和资源认证才可以访问。但是细心想想,还是有一些不足,在一下节将对其进行优化,主要有以下几点
- 不支持AJAX的调用,目前只能重定向页面,这对于一些前后端分离的开发是不满足的
- 不支持前台FreeMarker模板页面元素的权限控制,包括按钮、文字等
- URL拦截冗余在代码,虽然说SpringBoot提倡JAVA Configuration配置,但我们还是想要单独写到配置文件,例如yml或是properties
Shiro-SpringBoot (一)相关推荐
- Shiro+springboot+mybatis+EhCache(md5+salt+散列)认证与授权-03
从上文:Shiro+springboot+mybatis(md5+salt+散列)认证与授权-02 当每次进行刷新时,都会从数据库重新查询数据进行授权操作,这样无疑给数据库造成很大的压力,所以需要引入 ...
- Shiro+springboot+mybatis(md5+salt+散列)认证与授权-02
代码延续地址:Shiro+springboot+mybatis(md5+salt+散列)认证与授权-01 1.创建t_role角色表(比如管理员admin,普通用户user等),创建t_pers权限表 ...
- 教你 Shiro + SpringBoot 整合 JWT
本篇文章将教大家在 shiro + springBoot 的基础上整合 JWT (JSON Web Token) 如果对 shiro 如何整合 springBoot 还不了解的可以先去看我的上一篇文章 ...
- Shiro教程_2 Shiro+SpringBoot+Mysql+Redis(缓存)
源代码 https://gitee.com/fakerlove/Shiro Shiro+SpringBoot+Mysql+Redis(缓存) 1. 添加依赖 <?xml version=&quo ...
- Shiro+springboot+mybatis(md5+salt+散列)认证与授权-01
这个小项目包含了注册与登录,使用了springboot+mybatis+shiro的技术栈:当用户在浏览器登录时发起请求时,首先这一系列的请求会被拦截器进行拦截(ShiroFilter),然后拦截器根 ...
- shiro+springboot分析思路
文章目录 前言 一.为什么要使用shiro 二.使用步骤 1.如何认证和授权 2.如何获取数据 总结 前言 shiro和spring security等安全框架可以用户管理和权限认证 一.为什么要使用 ...
- Spring Boot整合Shiro + Springboot +vue
目录 02 Spring Boot整合Shiro p1.shiro概述 1 什么是Shiro 2 Shiro核心组件 p2.Shiro实现登录认证 AccountRealm.java QueryWra ...
- Shiro+SpringBoot 时,anon配置的匿名路径被拦截,自定义配置类走过的坑
最开始一直不去自定配置类,究其原因发现是少了: /*** Shiro配置类*/ @Configuration 少了@Configuration,这个注解配置. 一路顺畅的走了下来: 是不是要美滋滋的走 ...
- shiro springboot 整合
目录 shiro 介绍 shiro 名词解释 shiro 框架结构 认证过程 授权流程 与spring boot 整合 目录结构 POM依赖 Application.yml SQL脚本 实体 DAO, ...
- shiro+springboot自定义sessionId
在shiro中,默认返回的sessionId是uuid或者是random随机的,我们可能需要根据我们的需求进行重写,需要重写sessionId我们只需要写一个类实现SessionIdGenerator ...
最新文章
- 迅达云成参观学习---感谢信
- IC攻城狮求职宝典 01 2018年IC设计企业 笔试题 01 英伟达(Nvidia)
- import caffe失败 No module named caffe
- 浙大1202 zoj1202
- mongo执行逻辑表达式_MongoDB 常用查询操作
- ASCIIUNICODE编码演化
- select min from 连接
- Nginx是什么 ? 能干嘛 ?
- 使用AdapterTypeRender对不同类型的item数据到UI的渲染
- javascript定时器的计时事件
- ipad一直卡在白苹果_近万字多图带你玩转iPad——iPad指南
- 51单片机DS1302时钟
- 一周市场摘抄20210125
- 计算机网卡不连接网络连接怎么办,台式机无线网卡连接不上网络怎么办
- 数据库的ACID是什么
- 可验证随机函数(Verifiable Random Function, VRF)
- 三步解决NLP数据标注难题,百度大脑EasyDL专业版上线文本智能标注功能
- 商业模式与盈利模式的区别
- 处理idcard中的特殊字符
- JAVA配置多源数据库
热门文章
- 《石油地球物理测井——在井下看油气藏》 知识整理
- ffmpeg实现摄像头拉流_利用ffmpeg一步一步编程实现摄像头采集编码推流直播系统...
- 摄像头各参数的意义_如何选择摄像头,需要考虑那些参数
- 直播系统开发之ios对接腾讯云直播sdk
- 中国微量营养素市场趋势报告、技术动态创新及市场预测
- 粗糙集理论应用的实例
- 开启oracle的acfs,配置OracleACFS集群文件系统
- ZooKeeper学习笔记(八):ZooKeeper集群写数据原理
- 越豪华越危险 家装豪华程度与环境污染成正比
- 黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难——讲义