发表于: 2019-11-07 21:41:11

1 813


一、今天完成的事

1.学习shiro

1.shiro介绍

Shiro是一个Java安全框架,执行身份验证、授权、密码、会话管理。Shiro是Apache 的一个开源项目,前身是JSecurity 项目,始于2003年初。

Shiro 可以为任何应用提供安全保障 - 从命令行应用、移动应用到大型网络及企业应用。

shiro 解决了应用安全的四要素:

  • 认证 - 用户身份识别,常被称为用户“登录”;

  • 授权 - 访问控制;

  • 密码加密 - 保护或隐藏数据防止被偷窥;

  • 会话管理 - 每用户相关的时间敏感的状态。

同时,Shiro另外支持了一些辅助特性:如 Web 应用安全、单元测试和多线程,它们的存在强化了上面提到的四个要素。

2.shiro的优势

1、易于使用 - 易用性是这个项目的最终目标。应用安全有可能会非常让人糊涂,令人沮丧,并被认为是“必要之恶”【译注:比喻应用安全方面的编程。】。若是能让它简化到新手都能很快上手,那它将不再是一种痛苦了。

2、广泛性 - 没有其他安全框架可以达到 Apache Shiro 宣称的广度,它可以为你的安全需求提供“一站式”服务。

3、灵活性 - Apache Shiro 可以工作在任何应用环境中。虽然它工作在 Web、EJB 和 IoC 环境中,但它并不依赖这些环境。Shiro 既不强加任何规范,也无需过多依赖。

4、Web 能力 - Apache Shiro 对 Web 应用的支持很神奇,允许你基于应用 URL 和 Web 协议(如 REST)创建灵活的安全策略,同时还提供了一套控制页面输出的 JSP 标签库。

5、可插拔 - Shiro 干净的 API 和设计模式使它可以方便地与许多的其他框架和应用进行集成。你将看到 Shiro 可以与诸如 Spring、Grails、Wicket、Tapestry、Mule、Apache Camel、Vaadin 这类第三方框架无缝集成。

6、支持 - Apache Shiro 是 Apache 软件基金会成员,这是一个公认为了社区利益最大化而行动的组织。项目开发和用户组都有随时愿意提供帮助的友善成员。

3.核心概念

Shiro的核心概念有三个:Subject,SecurityManager 和 Realms。

1.subject

subject 被Shiro 描述为一个主体,对于web应用来说,可以简单理解为用户。

 Subject currentUser = SecurityUtils.getSubject(); 

获得Subject 后,通过这个对象,我们可以对其进行绝大多数安全操作:登录、登出、访问会话、执行授权检查等。

2.SecurityManager

Subject 的幕后推手是 SecurityManager,Subject 代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。

SecurityManager 是 Shiro 框架的核心,充当“保护伞”,引用了多个内部嵌套安全组件,它们形成了对象图。但是,一旦 SecurityManager 及其内部对象图配置好,它就会退居幕后,应用开发人员几乎把他们的所有时间都花在 Subject API 调用上。

一个应用只需要一个 SecurityManager,是一个单例对象。它的缺省实现是POJO,Shiro 里的其他组件也是一样。因此,可以用POJO兼容的任何配置机制进行配置:普通的Java代码、Spring xml、YAML、和 ini 文件等。基本上,能够实例化类和调用JavaBean兼容方法的任何配置形式都可以。

3.Realm

Realm 充当了 Shiro 与应用安全数据间的“桥梁”或者“连接器”。当切实与像用户帐户这类安全相关数据进行交互,执行认证(登录)和授权(访问控制)时,Shiro 会从应用配置的 Realm 中查找很多内容。

从某种意义上讲,Realm 实际上就是一个安全相关的 DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给 Shiro。

注意:在配置Shiro 时,必须指定至少一个 Realm ,可以配置多个。

Shiro 内置了一些Realm ,支持多种数据源的连接,如JDBC、LDAP、INI文件的连接等。另外,可以自定义Realm 实现,方便个性化的应用场景。

4.如何使用shiro
  • 在配置文件中定义需要给权限的目标

  • 在程序中调用subject进行验证。

5.在springboot中用shiro

导入依赖

<dependency>    
   <groupId>org.apache.shiro</groupId>    
   <artifactId>shiro-spring</artifactId>    
   <version>1.3.2</version>
</dependency>

springboot中集成shiro相对简单,只需要两个类:

  • shiroConfig

    就是对shiro的一些配置。

     package com.ksy.config;

    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.springframework.context.annotation.Bean;

    import java.util.LinkedHashMap;
    import java.util.Map;

    /**
    * @author shiyang
    * @PackageName com.ksy.config
    * @ClassName demo
    * @Description
    * @create 2019-11-07 20:09
    */
    public class ShiroConfig {
    /**
    * 一个过滤器,拦截url
    * @param securityManager
    * @return
    */
     @Bean(name = "shiroFilter")
     public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
       ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
       //必须set项
       shiroFilterFactoryBean.setSecurityManager(securityManager);
       //设置登录页面
       shiroFilterFactoryBean.setLoginUrl("/login");
       //设置登录成功跳转页面
       shiroFilterFactoryBean.setSuccessUrl("/home");
       //权限不足跳转的页面
       shiroFilterFactoryBean.setUnauthorizedUrl("/register");
       //拦截器,下面的属性就是配置不会被拦截的url
       Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
       // authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问,封装在DefaultWebSecurityManager中
       filterChainDefinitionMap.put("/home","anon");
       //这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截 剩余的都需要认证
       filterChainDefinitionMap.put("/**", "authc");
       shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
       return shiroFilterFactoryBean;
     }

    @Bean
    public SecurityManager securityManager() {
     DefaultWebSecurityManager defaultWebSecurityManager = new
     DefaultWebSecurityManager();
     defaultWebSecurityManager.setRealm(customRealm());
      return defaultWebSecurityManager;
    }

    @Bean
    public CustomRealm customRealm() {
       CustomRealm customRealm = new CustomRealm();
       return customRealm;
    }
    }

shiroFilter方法: 这个方法看名字就知道了:shiro的过滤器,可以设置登录页面(setLoginUrl)、权限不足跳转页面(setUnauthorizedUrl)、具体某些页面的权限控制或者身份认证。 注意:这里是需要设置SecurityManager(setSecurityManager)。 默认的过滤器还有:anno、authc、authcBasic、logout、noSessionCreation、perms、port、rest、roles、ssl、user过滤器。 具体的大家可以查看package org.apache.shiro.web.filter.mgt.DefaultFilter。这个类,常用的也就authc、anno。 securityManager 方法: 查看源码可以知道 securityManager是一个接口类,我们可以看下它的实现类:

由于项目是一个web项目,所以我们使用的是DefaultWebSecurityManager ,然后设置自己的Realm。  

  • CustonRealme类

自定义的CustonRealme继承AuthorizingRealm。并且重写父类中的doGetAuthorizationInfo(权限相关)、doGetAuthenticationInfo(身份验证)这两个方法。

package com.ksy.config;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import java.util.HashSet;
import java.util.Set;

/**
* @author shiyang
* @PackageName com.ksy.config
* @ClassName demo
* @Description
* @create 2019-11-07 20:44
*/

public class CustomRealm extends AuthorizingRealm {

   /**
    *  权限认证,即登录过后,每个身份不一定,对应的所能看的页面也不一样。
    * @param principalCollection
    * @return
    */
   @Override
   protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
       String uesrname = (String) SecurityUtils.getSubject().getPrincipal();
       SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
       Set<String> stringSet = new HashSet<>();
       stringSet.add("user:");
       stringSet.add("user");
       info.setStringPermissions(stringSet);
       return info;
   }

   /**
    * 身份认证。即登录通过账号和密码验证登陆人的身份信息。
    * @param authenticationToken
    * @return
    * @throws AuthenticationException
    */
   @Override
   protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

       System.out.println("-------身份认证方法--------");

       //getPrincipal()返回验证后用户名

       String userName = (String) authenticationToken.getPrincipal();

      //返回验证后的密码

       String userPwd = new String((char[]) authenticationToken.getCredentials());
       //根据用户名从数据库获取密码
       List<> userList = sysUserService.selectByMap(map);
       if(userList.size()!=0){
           user = userList.get(0);
       }
       String password = "123";
       if (userName == null) {
           throw new AccountException("用户名不正确");
       } else if (!userPwd.equals(password )) {
           throw new AccountException("密码不正确");
       }
       return new SimpleAuthenticationInfo(userName, password,getName());
   }
}

说明: 自定义的Realm类继承AuthorizingRealm类,并且重载doGetAuthorizationInfo和doGetAuthenticationInfo两个方法。 doGetAuthorizationInfo: 权限认证,即登录过后,每个身份不一定,对应的所能看的页面也不一样。 doGetAuthenticationInfo:身份认证。即登录通过账号和密码验证登陆人的身份信息。  




二、遇到的问题

关于shiro自定义验证还没有写完,学习的demo是死数据,想通过数据库获取用户名密码来拉验证,在springboot中user类还没写完,明天在看一看怎么实现,其他的看了源码大概理解shiro是怎么实现的。



三、收获

四、明天的计划

解决上述问题



返回列表 返回列表
评论

    分享到