1、shiro是什么、能做什么

    Apache Shiro是一个强大而灵活的开源安全框架,可以干净地处理身份验证,授权,企业会话管理和加密。

    • 验证用户验证他们的身份
    • 为用户执行访问控制,如:
      • 确定用户是否被分配了一定的安全角色
      • 确定用户是否被允许做某事
    • 在任何环境中使用Session API,即使没有Web或EJB容器。
    • 在身份验证,访问控制或会话生命周期内对事件作出反应。
    • 聚合1个或更多的用户安全数据数据源,并将其全部显示为单个复合用户视图。
    • 启用单点登录(SSO)功能
    • 为用户关联启用“记住我”服务,无需登录

    2、Shiro 的优点

    • 简单的身份认证, 支持多种数据源
    • 对角色的简单的授权, 支持细粒度的授权(方法级)
    • 支持一级缓存,以提升应用程序的性能;
    • 内置的基于 POJO 企业会话管理, 适用于 Web 以及非 Web 的环境
    • 非常简单的加密 API
    • 不跟任何的框架或者容器捆绑, 可以独立运行

    3、Shiro 架构 3 个核心组件

    • Subject: 正与系统进行交互的人, 或某一个第三方服务.
      • 所有 Subject 实例都被绑定到(且这是必须的)一个SecurityManager 上。
    • SecurityManager: Shiro 架构的心脏, 用来协调内部各安全组件, 管理内部组件实例, 并通过它来提供安全管理的各种服务.
      • 当 Shiro 与一个 Subject 进行交互时, 实质上是幕后的SecurityManager 处理所有繁重的 Subject 安全操作。
    • Realms: 本质上是一个特定安全的 DAO. 当配置 Shiro 时, 必须指定至少一个 Realm 用来进行身份验证和/或授权.
      • Shiro 提供了多种可用的 Realms 来获取安全相关的数据. 如关系数据库(JDBC), INI 及属性文件等.
      • 可以定义自己 Realm 实现来代表自定义的数据源。

    4、Shiro认证过程

    • 应用程序代码调用Subject.login 方法,传递创建好的包含终端用户的 Principals(身份)和 Credentials(凭证)的 AuthenticationToken 实例
    • Subject 实例: 通常为DelegatingSubject(或子类)委托应用程序的 SecurityManager 通过调用securityManager.login(token) 开始真正的验证。
    • SubjectManager 接收 token,调用内部的 Authenticator 实例调用 authenticator.authenticate(token).Authenticator 通常是一个ModularRealmAuthenticator 实例, 支持在身份验证中协调一个或多个Realm 实例
    • 如果应用程序中配置了一个以上的 Realm, ModularRealmAuthenticator 实例将利用配置好的AuthenticationStrategy来启动 Multi-Realm 认证尝试. 在Realms 被身份验证调用之前, 期间和以后,AuthenticationStrategy 被调用使其能够对每个Realm 的结果作出反应.
    • 每个配置的 Realm 用来帮助看它是否支持提交的AuthenticationToken. 如果支持, 那么支持 Realm 的 getAuthenticationInfo 方法将会伴随着提交的 token 被调用.getAuthenticationInfo 方法有效地代表一个特定 Realm 的单一的身份验证尝试。

    5、Shiro授权过程

    • 应用程序或框架代码调用任何Subject 的hasRole, checkRole, isPermitted,或者checkPermission方法的变体, 传递任何所需的权限
    • Subject 的实例—通常是DelegatingSubject(或子类), 调用securityManager 的对应的方法.
    • SecurityManager 调用 org.apache.shiro.authz.Authorizer 接口的对应方法.默认情况下,authorizer实例是一个 ModularRealmAuthorizer 实例, 它支持协调任何授权操作过程中的一个或多个Realm 实例
    • 每个配置好的 Realm 被检查是否实现了相同的Authorizer 接口. 如果是, Realm 各自的 hasRole, checkRole,isPermitted,或 checkPermission 方法将被调用。

    6、如何在spring中使用shiro

    • 在 web.xml 中配置 Shiro 的 Filter
    • 在 Spring 的配置文件中配置 Shiro:
      • 配置自定义 Realm:实现自定义认证和授权
      • 配置 Shiro 实体类使用的缓存策略
      • 配置 SecurityManager
      • 配置保证 Shiro 内部 Bean 声明周期都得到执行的 Lifecycle Bean 后置处理器
      • 配置AOP 式方法级权限检查
      • 配置 ShiroFilter

    7、shiro配置文件权限的字符串表示方式

    • 权限字符串的规则是:“资源标识符:操作:资源实例标识符”,意思是对哪个资源的哪个实例具有什么操作,“:”是资源/操作/实例的分割符,权限字符串也可以使用*通配符。
    • Eeample
      • 用户创建权限:user:create,或user:create:*
      • 用户修改实例001的权限:user:update:001
      • 用户实例001的所有权限:user:*:001

    8、shiro的加密子系统有什么
    image.png

    • 重点讲shiro提供的第二种:不可逆加密。

    散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,常见的散列算法如MD5、SHA等。一般进行散列时最好提供一salt(盐),比如加密密码“admin”,产生的散列值是“21232f297a57a5a743894a0e4a801fc3”,可以到一些md5解密网站很容易的通过散列值得到密“admin”,即如果直接对密码进行散列相对来说破解更容易,此时我们可以加一些只有系统知道的干扰数据,如用户名和ID(即盐);这样散列的对象是“密码+用户名+ID”,这样生成的散列值相对来说更难破解。

    9、shiro在spring文件中怎么配置缓存

    1. <dependency>
    2. <groupId>org.apache.shiro</groupId>
    3. <artifactId>shiro-ehcache</artifactId>
    4. <version>1.3.0</version>
    5. </dependency>
    • 定义配置文件
    1. <?xml version="1.1" encoding="UTF-8"?>
    2. <ehcache name="shirocache">
    3. <diskStore path="java.io.tmpdir"/>
    4. <defaultCache
    5. maxElementsInMemory="3000"
    6. eternal="true"
    7. timeToIdleSeconds="120"
    8. timeToLiveSeconds="120"
    9. overflowToDisk="true"/>
    10. <cache name="passwordRetryCache"
    11. maxElementsInMemory="3000"
    12. eternal="false"
    13. timeToIdleSeconds="300"
    14. timeToLiveSeconds="0"
    15. overflowToDisk="false">
    16. </cache>
    17. <cache name="authorizationCache"
    18. maxElementsInMemory="3000"
    19. eternal="false"
    20. timeToIdleSeconds="1800"
    21. timeToLiveSeconds="0"
    22. overflowToDisk="false">
    23. </cache>
    24. <cache name="authenticationCache"
    25. maxElementsInMemory="3000"
    26. eternal="false"
    27. timeToIdleSeconds="1800"
    28. timeToLiveSeconds="0"
    29. overflowToDisk="false">
    30. </cache>
    31. <cache name="shiro-activeSessionCache"
    32. maxElementsInMemory="3000"
    33. eternal="false"
    34. timeToIdleSeconds="1800"
    35. timeToLiveSeconds="0"
    36. overflowToDisk="false">
    37. </cache>
    • 在此配置文件之中实际上有以下几个核心选项:

      • “diskStore path=”java.io.tmpdir”:磁盘的存储目录;
      • name=”*””:对要进行缓存的项进行一个标注;
      • “maxElementsInMemory=”3000”:可以缓存的最大的对象个数;
      • “eternal=”false”:是否允许自动失效(如果某一个对象长时间不使用);
      • “timeToIdleSeconds=”1800”:最小的失效时间,1800秒;
      • “timeToLiveSeconds=”0”:最大的保存时间,单位是秒;
      • “overflowToDisk=”false”:如果容量过多,可以将其保存在磁盘
    • 如果要想使缓存生效,则还需要修改applicationContext.xml文件进行缓存配置:

      • 定义缓存管理器:
    1. <!-- 进行缓存的操作配置 -->
    2. <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
    3. <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
    4. </bean>
    • 在安全管理器之中注册此缓存管理器:
    1. <!-- 配置SecurityManager的管理 -->
    2. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    3. <!-- 配置你需要使用的Realms -->
    4. <property name="realm" ref="memberRealm"/>
    5. <property name="cacheManager" ref="cacheManager"/>
    6. </bean>

    10、shiro如何实现单点登录和多点登录

    • 单点登录
    1. import org.apache.shiro.session.Session;
    2. import org.apache.shiro.session.mgt.eis.SessionDAO;
    3. public class MyShiroRealmDemo extends AuthorizingRealm {
    4. private static final Logger logger = LoggerFactory.getLogger(MyShiroRealmDemo.class);
    5. @Autowired
    6. private SessionDAO sessionDAO;
    7. @Override
    8. protected AuthenticationInfo doGetAuthenticationInfo(
    9. AuthenticationToken authcToken) throws AuthenticationException {
    10. UsernamePasswordCaptchaToken token = (UsernamePasswordCaptchaToken) authcToken;
    11. //从token中获取用户名
    12. String loginName = token.getUsername();
    13. // 踢出已登录的用户
    14. Collection<Session> sessions = sessionDAO.getActiveSessions();
    15. for (Session session : sessions) {
    16. if (loginName.equals(String.valueOf(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY)))) {
    17. session.setTimeout(0);// 设置session为0,即立即失效,将其踢出系统
    18. break;
    19. }
    20. }
    21. /***/
    22. }

    参考