认证与授权 --- Shiro(一)

认证与授权 — Shiro(一)

认证与授权一般主流的框架就是 ShiroSpringSecurity, Shiro 相对来说较于简单, 而且我们注意到一个神奇的东东, Spring 竟然也在用 Shiro

file

真是有图有真相啊…

file

而且帅帅最近和朋友一起开发的项目也使用了 Shiro, 因此做一些 Shiro 的分享.

1. Shiro 简介

  • Apache Shiro 是 Java 的一个安全(权限)框架
  • Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在 JavaSE 环境,也可以用在 JavaEE 环境
  • Shiro 可以完成:认证、授权、加密、会话管理、与Web 集成、缓存 等

2. 功能简介

Apache Shiro是具有许多功能的全面的应用程序安全框架。下图显示了Shiro的核心功能:

file

Shiro以Shiro开发团队所谓的“应用程序安全性的四个基石”为目标-身份验证,授权,会话管理和加密:

  • Authentication:身份认证/登录,验证用户是不是拥有相应的身份;
  • Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用 户是否能进行什么操作,如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户 对某个资源是否具有某个权限;
  • Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有 信息都在会话中;会话可以是普通 JavaSE 环境,也可以是 Web 环境的;
  • Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;

在不同的应用程序环境中,还具有其他功能来支持和加强这些问题,主要有:

  • Web Support:Web 支持,可以非常容易的集成到Web 环境;
  • Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可 以提高效率;
  • Concurrency:Shiro 支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能
  • 把权限自动传播过去;
  • Testing:提供测试支持;
  • Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
  • Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登 录了

3. Shiro 架构

3.1 从 Shiro 外部来看

file

  • Subject:应用代码直接交互的对象是 Subject,也就是说 Shiro 的对外 API 核心就是 Subject。Subject 代表了当前“用户”, 这个用户不一定 是一个具体的人,与当前应用交互的任何东西都是 Subject,如网络爬虫, 机器人等;与 Subject 的所有交互都会委托给 SecurityManager; Subject 其实是一个门面,SecurityManager 才是实际的执行者;
  • SecurityManager:安全管理器;即所有与安全有关的操作都会与 SecurityManager 交互;且其管理着所有 Subject;可以看出它是 Shiro 的核心,它负责与 Shiro 的其他组件进行交互,它相当于 SpringMVC 中 DispatcherServlet 的角色
  • Realm:Shiro 从 Realm 获取安全数据(如用户、角色、权限),就是说 SecurityManager 要验证用户身份,那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色/ 权限进行验证用户是否能进行操作;可以把 Realm 看成 DataSource

3.2 从 Shiro 内部来看

file

  • Subject: 任何可以与应用交互的“用户”;
  • SecurityManager : 相当于SpringMVC 中的 DispatcherServlet;是 Shiro 的核心; 所有具体的交互都通过 SecurityManager 进行控制;它管理着所有 Subject、且负责进 行认证、授权、会话及缓存的管理。
  • Authenticator: 负责 Subject 认证,是一个扩展点,可以自定义实现;可以使用认证策略(Authentication Strategy),即什么情况下算用户认证通过了;
  • Authorizer: 授权器、即访问控制器,用来决定主体是否有权限进行相应的操作;即控 制着用户能访问应用中的哪些功能;
  • Realm:可以有 1 个或多个 Realm,可以认为是安全实体数据源,即用于获取安全实体的;可以是JDBC 实现,也可以是内存实现等等;由用户提供;所以一般在应用中都需要实现自己的 Realm;
  • SessionManager: 管理 Session 生命周期的组件;而 Shiro 并不仅仅可以用在 Web 环境,也可以用在如普通的 JavaSE 环境
  • CacheManager: 缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据基本上很少改变,放到缓存中后可以提高访问的性能
  • Cryptography: 密码模块,Shiro 提高了一些常见的加密组件用于如密码加密/解密。

4. Quickstart

Shiro 为我们提供了一些入门学习的实例代码, 我们可以下载 https://downloads.apache.org/shiro/1.5.3/shiro-root-1.5.3-source-release.zip 学习.

4.1 创建一个 Maven 项目

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>

   <groupId>club.javafamily</groupId>
   <artifactId>shiro01</artifactId>
   <version>1.0-SNAPSHOT</version>

   <properties>
      <log4j.version>1.2.17</log4j.version>
      <slf4j.version>1.7.26</slf4j.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-core</artifactId>
         <version>1.4.2</version>
      </dependency>
      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>jcl-over-slf4j</artifactId>
         <scope>runtime</scope>
         <version>${slf4j.version}</version>
      </dependency>
      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-log4j12</artifactId>
         <scope>runtime</scope>
         <version>${slf4j.version}</version>
      </dependency>
      <dependency>
         <groupId>log4j</groupId>
         <artifactId>log4j</artifactId>
         <scope>runtime</scope>
         <version>${log4j.version}</version>
      </dependency>

   </dependencies>

</project>

4.2 Log4j.properties

# 注意我这里把 Log 级别提到了 Error
log4j.rootLogger=ERROR, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n

# General Apache libraries
log4j.logger.org.apache=WARN

# Spring
log4j.logger.org.springframework=WARN

# Default Shiro logging
log4j.logger.org.apache.shiro=INFO

# Disable verbose logging
log4j.logger.org.apache.shiro.util.ThreadContext=WARN
log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN

4.3 shiro.ini

[users]
# 用户 jack, 密码为 JavaFamily, 拥有 dev 和 test 两个 role
jack = JavaFamily, dev, test

[roles]
# admin role 拥有所有权限
admin = *
# dev role
dev = code:commit, code:checkout, code:test:write, code:test:read
# test role
test = code:checkout, code:test:read

** 使用 * 表示 role 拥有所有权限 **

4.4 创建程序入口类 Quickstart.java 并检查代码结构

file

4.5 代码分析

package club.javafamily.shiro01;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;

public class Quickstart {

    public static void main(String[] args) {

        // 通过 ini 文件创建一个 SecurityManager 的工厂(生产环境不会这么用)
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        // 获取 SecurityManager
        SecurityManager securityManager = factory.getInstance();

        // 设置 SecurityManager 为单例, 以后通过 SecurityUtils(与 Spring 整合后没有意义)
        SecurityUtils.setSecurityManager(securityManager);

        // 获取 Subject 对象
        Subject currentUser = SecurityUtils.getSubject();

        // 测试使用 Session 对象 ---> 注意这是 SE 项目, 不是 web 项目, 依然可以用 Session
        Session session = currentUser.getSession();
        session.setAttribute("someKey", "aValue");
        String value = (String) session.getAttribute("someKey");

        System.out.println("===测试 Session 对象: someKey = " + value);

        // 测试登录
        if (!currentUser.isAuthenticated()) { // 如果用户没有登录
            // 通过用户名和密码构造 UsernamePasswordToken 用于验证
            // 这里的的 jack---JavaFamily 用户名和密码来自于 shiro.ini 文件
            UsernamePasswordToken token = new UsernamePasswordToken("jack", "JavaFamily");
            // 设置 RememberMe
            token.setRememberMe(true);
            try {
                // 执行登录
                currentUser.login(token);
            } catch (UnknownAccountException uae) {
                System.out.println("账户不存在" + token.getPrincipal());
                return;
            } catch (IncorrectCredentialsException ice) {
                System.out.println("密码不正确: " + token.getPrincipal());
                return;
            } catch (LockedAccountException lae) {
                System.out.println("账户已经登录: " + token.getPrincipal());
                return;
            }
            catch (AuthenticationException ae) {
                System.out.println("登录失败! 请过会再试!");
                return;
            }
        }

        System.out.println("用户 " + currentUser.getPrincipal() + " 已成功登录!");

        // 测试 Role
        if (currentUser.hasRole("dev")) {
            System.out.println("用户" + currentUser.getPrincipal() + " 属于 dev Role");
        } else {
            System.out.println("用户" + currentUser.getPrincipal() + " 不是 dev Role");
        }

        // 测试权限
        if (currentUser.isPermitted("code:commit")) {
            System.out.println("用户 " + currentUser.getPrincipal() + " 拥有代码提交的权限.");
        } else {
            System.out.println("用户 " + currentUser.getPrincipal() + " 没有代码提交的权限.");
        }

        if (currentUser.isPermitted("code:test:write")) {
            System.out.println("用户 " + currentUser.getPrincipal() + " 拥有 code:test:write 权限");
        } else {
            System.out.println("用户 " + currentUser.getPrincipal() + " 没有 code:test:write 权限");
        }

        if (currentUser.isPermitted("code:test:delete")) {
            System.out.println("用户 " + currentUser.getPrincipal() + " 拥有 code:test:delete 权限");
        } else {
            System.out.println("用户 " + currentUser.getPrincipal() + " 没有 code:test:delete 权限");
        }


        //注销
        currentUser.logout();

        System.exit(0);
    }
}

** 分析帅帅已经用注释给大家标注了, 就不多啰嗦了. **

4.6 运行结果

file

** 最近几期文章可能都是关于 Shiro 的哦, 大家不要着急, 因为最近和朋友开发一个项目要用, 所以临时做一些 Shiro 的学习分享, 后面也有 Spring Security 系列的, 感兴趣的持续关注哦! **

file

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值