shiro笔记

2022/4/8 23:23:28

本文主要是介绍shiro笔记,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

shiro笔记

shiro简述

  • Apache Shiro 是java的一个安全框架
  • Shiro 可以做:认证、授权、加密、会话管理、Web集成、缓存等功能。
  • 官网:http://shiro.apache.org/

功能介绍

  1. Authentication:身份认证/登录,验证用户是不是拥有相应的身份
  2. Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;
  3. Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通 JavaSE 环境,也可以是 Web 环境的;
  4. Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
  5. Web Support:Web 支持,可以非常容易的集成到Web 环境;
  6. Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;
  7. Concurrency:Shiro 支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
  8. Testing: 提供 测试 支持
  9. Run As: 允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
  10. Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了

Shiro与Spring Security对比

共同点: 认证、授权、加密、会话、缓存、remember Me功能...
不同点: Shiro配置和使用比较简单,Spring Sccurity上手复杂.Shiro依赖性低,不需要任何框架和容器,可以独立运行,而Spring Security依赖于Spring容器.

Shiro四大核心功能

Authentication - 身份认证:
一般用于登录:登陆时,验证用户是否拥有相应身份。
Authorization - 访问控制:
验证已认证用户是否拥有某些权限,可以让他进行权限内的操作。
Cryptography - 密码加密:
将密码加密储存到数据库,而不是明文储存,可以保护数据的安全性。
Session Management - 会话管理:
用户登录后就是第一次会话,在会话结束(退出登录)前,他所有的信息都在会话中。

Shiro三个核心组件

Subject-主体:

应用代码直接交互的对象是Subject,也就是说Shiro的对外API核心是Subject。
Subject的所有交互都会委托给SecurityManager(实际的执行者)。

SecurityManager-安全管理器:

SecurityManager是Shiro的核心,负责与Shiro的其他组件进行交互,相当于SpringMVC中DispatcherServlet的角色。
它管理着所有 Subject、且负责进行认证和授权、及会话、缓存的管理,所有具体的交互都通过SecurityManager 进行控制。
SecurityManager是一个单例对象,一个应用中只需要一个SecurityManager.

Realm-域

Shiro从Realm获取安全数据(如用户、角色、权限),
就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;
也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;
可以把Realm看成DataSource,即安全数据源。

shiro中的认证

身份认证,就是判断一个用户是否为合法用户的处理过程。最常见的简单身份验证方式是通过核对用户输入的用户名和口令,看其是否与系统中存储的该用户的用户名和口令一致,来判断用户身份是否正确。

shiro中认证的关键对象

  • Subject:主体
    访问系统的用户,主体可以是用户、程序等。
  • Principal:身份信息
    是主体进行身份认证的标识,标识必须具有唯一性,如用户名、手机号、邮箱地址等。一个主体可以有多个身份,但是必须有一个主身份(Primary Principal)。
  • credential:凭证信息
    是只有主体自己知道的安全信息,如密码、证书等。

认证流程

image

认证的开发

  1. 创建Spring Boot项目
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-core</artifactId>
  <version>1.5.3</version>
</dependency>
  1. 引入shiro配置文件
    配置文件:名称随意,以 .ini结尾,放在resources目录下。

注意:在实际的项目开发中并不会使用这种方式,这种方法可以用来初学时练手!

[users]
king=123456
wang=123456
  1. 开发认证代码
public class ShiroDemo{
	public static void main(String[] args){
		//1.创建安全管理器对象
		DefaultSecurityManager securityManager = new DefaultSecurityManager();
		//2.给安全管理器设置realm
		securityManager.setRealm(new InitRealm("classpath:shiro.ini"));
		//3.SecurityUtils全局安全工具类设置安全管理器
		SecurityUtils.setSecurityManager(securityManager);
		//4.关键对象subject主体
		Subject subject = SecurityUtils.getSubject();
		//5.创建令牌
		UsernamePasswordToken token = new UsernamePasswordToken("king","123456");
		try{
			System.out.println("认证状态"+subject.isAuthenticated());//fasle
			//用户认证
            subject.login(token);
            System.out.println("认证状态"+subject.isAuthenticated());
		}catch(UnknownAccountException e){
			e.printStackTrace();
            System.out.println("认证失败,用户名不存在");
		}catch(IncorrectCredentialsException e){
			e.printStackTrace();
            System.out.println("认证失败,密码错误");
		}
	}
}
  1. 常见的异常类型
  • DisabledAccountException(帐号被禁用)
  • LockedAccountException(帐号被锁定)
  • ExcessiveAttemptsException(登录失败次数过多)
  • ExpiredCredentialsException(凭证过期)等

自定义Realm

通过分析源码可得,

  1. 最终执行用户名比较的的是 在SimpleAccountRealm类 的doGetAuthenticationInfo 方法完成用户名校验。
  2. 最终密码校验是在 AuthenticatingRealm类 的 assertCredentialsMatch方法 中。
    shiro提供的Realm
    image
    根据认证源码认证使用的是SimpleAccountRealm
    image
public class SimpleAccountRealm extends AuthorizingRealm{
	//......省略
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        SimpleAccount account = getUser(upToken.getUsername());

        if (account != null) {

            if (account.isLocked()) {
                throw new LockedAccountException("Account [" + account + "] is locked.");
            }
            if (account.isCredentialsExpired()) {
                String msg = "The credentials for account [" + account + "] are expired";
                throw new ExpiredCredentialsException(msg);
            }

        }

        return account;
    }

    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = getUsername(principals);
        USERS_LOCK.readLock().lock();
        try {
            return this.users.get(username);
        } finally {
            USERS_LOCK.readLock().unlock();
        }
    }
}

接下里,开始自定义realm!

/**
 * 自定义Realm
 */
public class CustomerRealm extends AuthorizingRealm{
	//授权
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("==================");
        return null;
    }
	//认证
	@Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //在token中获取 用户名
        String principal = (String) token.getPrincipal();
        System.out.println(principal);

        //实际开发中应当 根据身份信息使用jdbc mybatis查询相关数据库
        //在这里只做简单的演示
        //假设username,password是从数据库获得的信息
        String username="zhangsan";
        String password="123456";
        if(username.equals(principal)){
            //参数1:返回数据库中正确的用户名
            //参数2:返回数据库中正确密码
            //参数3:提供当前realm的名字 this.getName();
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal,password,this.getName());
            return simpleAuthenticationInfo;
        }
        return null;
    }
}


这篇关于shiro笔记的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程