Shiro-SpringBoot (一)
创始人
2024-03-14 10:19:07

前不久负责项目中刚好也使用了Shiro做权限控制,趁着空闲期想把之前做的整理一下。在日常项目开发中,权限认证是不可少的模块。比较常用的有Spring Security,或是轻量级的Apache Shiro。相对来说Shiro提供了认证、授权、加密、会话管理、与Web集成、缓存等。这些都是日常会用到的,而且Shiro的API比较简洁,学习成本相对低。接下来将整理一下在SpringBoot中如何集成Shiro:

  • RBAC介绍
  • SpringBoot集成Shiro和配置
  • Shiro的登录和认证
  • 当前不足点

(一) RBAC介绍

**RBAC(Role-Based Access Control )**基于角色访问控制,在权限设计上用户是基于角色进行权限认证,而角色又是和资源相关联的。这样在设计和管理上简化了权限的操作,它们都是层级依赖,更方便我们的管理。如此一来,数据库表设计可以如下图:
cmd-markdown-logo

(二) SpringBoot集成Shiro和配置

1、导入Shiro依赖

pom.xml中加入以下依赖

org.apache.shiroshiro-spring1.2.5

2、配置Shiro

在配置之前,首先了解一下Shiro中主要功能,并看看它们主要是做什么的。

  • Subject 安全视角下与软件交互的实体(用户,第三方服务等等)
  • Authenticator 用户登录时进行账户的认证
  • Authorizer 用户登录时进行账户的权限资源认证
  • Realms每当执行认证或授权时,shiro会从程序配置的一个或多个Realm中查询

新建JAVAShiroRealm用于继承ShiroAuthorizingRealm抽象类,并复写doGetAuthenticationInfodoGetAuthorizationInfo用于账户和权限的认证。

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 userAuthorityInfoMap = userService.getUserAuthorityInfo(useCode);//这里可以从数据库进行查询List roles = new ArrayList();List perms = mew ArrayList();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 filterChainDefinitionMap = new LinkedHashMap();//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

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...