写在前面的话:

我之前写过两篇与shiro安全框架有关的博文,居然能够广受欢迎实在令人意外。说明大家在互联网时代大伙对于安全和登录都非常重视,无论是大型项目还是中小型业务,普遍都至少需要登录与认证的逻辑封装。相较于SpringSecurity而言,Shrio更轻量无过多依赖和便于独立部署的特点更收到开发者的欢迎。本篇博客只作为前两篇对于shiro使用的基础补充,我只谈谈如何在springboot项目中配置多角色验证。

一、场景介绍

假设在我们的项目中需要有前台用户登录和后台系统管理员登录两种验证方式。当然在传统的业务逻辑中用户和管理员可以使用不同的角色加以区分,假设现在的逻辑是用户与系统管理员分别保存在不同的表中并且也分别对应了不同的角色(role)与权限(permission)。换句话说,从业务上看相同的用户名和密码如果是在前台页面登录可能对应的是普通用户,从后台登录则对应某板块的系统管理。面对这样的需求我们可以在shiro框架中配置多个realm,再配合上认证策略来执行。

二、代码讲解

与单一realm相同,首先根据不同的登录认证要求创建不同的realm。这里只提供作为后台系统管理员的realm代码实例:

// 系统管理员专用
public class AdministratorRealm extends AuthorizingRealm {
@Autowired
private AdministratorRegisterService administratorRegisterService;
@Autowired
private PasswordSupport passwordSupport; @Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
String username = (String) principals.getPrimaryPrincipal();
Administrator administrator = administratorRegisterService.getAdministratorByName(username);
for (Role r : administrator.getRoles()) {
authorizationInfo.addRole(r.getRoleName());
}
return authorizationInfo;
} @Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
Administrator administrator = administratorRegisterService.getAdministratorByName(username);
if (administrator == null) {
throw new UnknownAccountException();
}
if (administrator.isLocked()) {
throw new LockedAccountException();
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(administrator.getUsername(),
administrator.getPassword(), ByteSource.Util.bytes(passwordSupport.credentialsSalt(administrator)),
getName()); return authenticationInfo;
} }

doGetAuthenticationInfo方法负责用户名和密码验证,doGetAuthorizationInfo方法负责角色和权限的分配, passwordSupport是一个自定义的类负责password加密和生成salt功能。

/**
* 密码辅助方法
*
* @author learnhow
*
*/
@Component
public class PasswordSupport {
public static final String ALGORITHM_NAME = "md5";
public static final int HASH_ITERATIONS = 2;/**
* 针对系统管理生成salt和加密密码
*
* @param administrator
*/
public void encryptPassword(Administrator administrator) {
administrator.setSalt(new SecureRandomNumberGenerator().nextBytes().toHex());
String newPassword = new SimpleHash(ALGORITHM_NAME, administrator.getPassword(),
ByteSource.Util.bytes(credentialsSalt(administrator)), HASH_ITERATIONS).toHex();
administrator.setPassword(newPassword);
}/**
* 对Administrator的salt生成规则
*
* @param administrator
* @return
*/
public String credentialsSalt(Administrator administrator) {
return administrator.getSalt() + administrator.getEmail();
}
}

AdministratorRegisterService是服务组件负责通过name从数据库中查询。

在Shiro中无论是单一realm还是多个realm都需要对SecurityManager进行配置。

@Configuration
public class ShiroConfig {
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName(PasswordSupport.ALGORITHM_NAME);
hashedCredentialsMatcher.setHashIterations(PasswordSupport.HASH_ITERATIONS);
return hashedCredentialsMatcher;
} @Bean
public AdministratorRealm getAdministatorRealm() {
AdministratorRealm realm = new AdministratorRealm();
realm.setName("AdministratorRealm");
realm.setCredentialsMatcher(hashedCredentialsMatcher());
return realm;
} @Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator();
modularRealmAuthenticator.setAuthenticationStrategy(new FirstSuccessfulStrategy());
securityManager.setAuthenticator(modularRealmAuthenticator); List<Realm> realms = new ArrayList<>();
// TODO-多个realms进配置在这里
realms.add(getAdministatorRealm());
securityManager.setRealms(realms);
return securityManager;
}
}

ModularRealmAuthenticator的setAuthenticationStrategy方法中配置认证策略。Shiro提供了三种策略:AllSuccessFulStrategy, AtLeastOneSuccessFulAtrategy, FirstSuccessFulStrategy,默认使用AtLeastOneSuccessFulAtrategy,通常不需要特别配置。

三、注意事项

1.多realm认证只会抛出AuthenticationException,因此如果要想在外部判断到底是在认证的哪一步发生的错误需要自己定义一些异常类型。

2.shiro没有提供根据条件指定realm的功能,如果需要实现这样的功能只能通过继承与重写来实现,这里没有涉及需要深入探讨的同学最好根据自己的实际情况专门研究。

写在后面的话:

最近有不少朋友在看了我的博客以后加我的QQ或者发邮件要求提供演示源码,为了方便交流我索性建了一个技术交流群,今后有些源码我可能就放群资料里面了。当然之前的一些东西还在补充中,有些问题也希望大伙能共同交流。QQ群号:960652410

30分钟了解Shiro与Springboot的多Realm基础配置的更多相关文章

  1. 30分钟带你了解Springboot与Mybatis整合最佳实践

    前言:Springboot怎么使用想必也无需我多言,Mybitas作为实用性极强的ORM框架也深受广大开发人员喜爱,有关如何整合它们的文章在网络上随处可见.但是今天我会从实战的角度出发,谈谈我对二者结 ...

  2. Shiro (Shiro + JWT + SpringBoot应用)

    Shiro (Shiro + JWT + SpringBoot应用) 目录 Shiro (Shiro + JWT + SpringBoot应用) 1.Shiro的简介 2.Shiro + JWT + ...

  3. 转:30分钟了解Springboot整合Shiro

    引自:30分钟了解Springboot整合Shiro 前言:06年7月的某日,不才创作了一篇题为<30分钟学会如何使用Shiro>的文章.不在意之间居然斩获了22万的阅读量,许多人因此加了 ...

  4. 30分钟学会如何使用Shiro

    本篇内容大多总结自张开涛的<跟我学Shiro>原文地址:http://jinnianshilongnian.iteye.com/blog/2018936 我并没有全部看完,只是选择了一部分 ...

  5. 转:30分钟学会如何使用Shiro

    引自:http://www.cnblogs.com/learnhow/p/5694876.html 本篇内容大多总结自张开涛的<跟我学Shiro>原文地址:http://jinniansh ...

  6. 30分钟学会如何使用Shiro(转自:http://www.cnblogs.com/learnhow/p/5694876.html)

    本篇内容大多总结自张开涛的<跟我学Shiro>原文地址:http://jinnianshilongnian.iteye.com/blog/2018936 我并没有全部看完,只是选择了一部分 ...

  7. 30分钟学会如何使用Shiro(转)

    本文转自http://www.cnblogs.com/learnhow/p/5694876.html 感谢作者 本篇内容大多总结自张开涛的<跟我学Shiro>原文地址:http://jin ...

  8. 30分钟学会如何使用Shiro(转)

    本篇内容大多总结自张开涛的<跟我学Shiro>原文地址:http://jinnianshilongnian.iteye.com/blog/2018936 我并没有全部看完,只是选择了一部分 ...

  9. 30分钟学会使用Spring Web Services基础开发

    时隔一年终于又推出了一篇30分钟系列,上一篇<30分钟学会反向Ajax>是2016年7月的事情了.时光荏苒,岁月穿梭.虽然一直还在从事Java方面的开发工作,但是私下其实更喜欢使用C++. ...

随机推荐

  1. Lintcode: k Sum II

    Given n unique integers, number k (1<=k<=n) and target. Find all possible k integers where the ...

  2. sql distinct去除重复

    distinct select  distinct * from  table1 或者用 group  by

  3. 问题排查之'org.apache.rocketmq.spring.starter.core.RocketMQTemplate' that could not be found.- Bean method 'rocketMQTemplate' in 'RocketMQAutoConfiguration' not loaded.

    背景 今天将一个SpringBoot项目的配置参数从原有的.yml文件迁移到Apollo后,启动报错“Bean method 'rocketMQTemplate' in 'RocketMQAutoCo ...

  4. AHB-Lite简介

    AHB总线实现了简单的基于burst的传输,数据总线带宽可配置32-1024bit.可以实现简单的fixed pipeline在address/control phase和 data phase之间. ...

  5. BP神经网络的Java实现(转)

    http://fantasticinblur.iteye.com/blog/1465497 课程作业要求实现一个BPNN.这次尝试使用Java实现了一个.现共享之.版权属于大家.关于BPNN的原理,就 ...

  6. linux常用命令:route 命令

    Linux系统的route 命令用于显示和操作IP路由表(show / manipulate the IP routing table).要实现两个不同的子网之间的通信,需 要一台连接两个网络的路由器 ...

  7. Linux基础命令---paste

    paste 将指定的文件按照列的方式合并,将结果显示到标准输出设备上,相当于两个并列的cat命令. 此命令的适用范围:RedHat.RHEL.Ubuntu.CentOS.SUSE.openSUSE.F ...

  8. 穿透内网,连接动态ip,内网ip打洞-----p2p实现原理

    转:http://blog.csdn.net/suhuaiqiang_janlay/article/details/60466333 本人找几篇讲得好的来整理一下. (1)问题的由来: (2)动态ip ...

  9. ELK学习笔记之CentOS 7下ELK(6.2.4)++LogStash+Filebeat+Log4j日志集成环境搭建

    0x00 简介 现在的公司由于绝大部分项目都采用分布式架构,很早就采用ELK了,只不过最近因为额外的工作需要,仔细的研究了分布式系统中,怎么样的日志规范和架构才是合理和能够有效提高问题排查效率的. 经 ...

  10. Python Web学习笔记之并发编程的孤儿进程与僵尸进程

    1.前言 之前在看<unix环境高级编程>第八章进程时候,提到孤儿进程和僵尸进程,一直对这两个概念比较模糊.今天被人问到什么是孤儿进程和僵尸进程,会带来什么问题,怎么解决,我只停留在概念上 ...