Shiro入门

Shiro入门

    • 引言
    • 题外话:安全框架Shiro和Spring Security比较
      • Shiro
      • Spring Security
  • 1. 什么是shiro
  • 2. 在应用程序角度来观察使用Shiro完成工作
  • 3. shiro架构
  • 4. Shiro身份验证(shiro.ini)
  • 5. Shiro权限认证(支持三种方式的授权)
  • 6. 授权
  • 7. shiro集成web(shiro-web.ini)
  • 8. 其它
  • 9. 配置文件
  • 10.shiro认证

引言

传统权限管理使用的是基于url拦截的权限管理方式,实现起来比较简单,不依赖于框架,使用web提供filter就可以实现,但是这种方式存在问题,需要将所有的url全部配置到xml中来,有些繁琐,不易维护,url资源和权限表示方式不规范。
Shiro入门_第1张图片

题外话:安全框架Shiro和Spring Security比较

Shiro

首先Shiro较之 Spring Security,Shiro在保持强大功能的同时,还在简单性和灵活性方面拥有巨大优势。

Shiro是一个强大而灵活的开源安全框架,能够非常清晰的处理认证、授权、管理会话以及密码加密。如下是它所具有的特点:

易于理解的 Java Security API;
简单的身份认证(登录),支持多种数据源(LDAP,JDBC,Kerberos,ActiveDirectory 等);
对角色的简单的签权(访问控制),支持细粒度的签权;
支持一级缓存,以提升应用程序的性能;
内置的基于 POJO 企业会话管理,适用于 Web 以及非 Web 的环境;
异构客户端会话访问;
非常简单的加密 API;
不跟任何的框架或者容器捆绑,可以独立运行。

Spring Security

除了不能脱离Spring,shiro的功能它都有。而且Spring Security对Oauth、OpenID也有支持,Shiro则需要自己手动实现。Spring Security的权限细粒度更高。

1. 什么是shiro

shiro是apache的一个开源框架,是一个权限管理的框架,实现 用户认证、用户授权。
spring中有spring security (原名Acegi),是一个权限框架,它和spring依赖过于紧密,没有shiro使用简单。
shiro不依赖于spring,shiro不仅可以实现 web应用的权限管理,还可以实现c/s系统,
分布式系统权限管理,shiro属于轻量框架,越来越多企业项目开始使用shiro。

2. 在应用程序角度来观察使用Shiro完成工作

Shiro入门_第2张图片
Subject:主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject 都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者;
SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager 交互;且它管理着所有Subject;可以看出它是Shiro 的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器;
Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。

3. shiro架构

Shiro入门_第3张图片
3.1 subject:主体,可以是用户也可以是程序,主体要访问系统,系统需要对主体进行认证、授权。
3.2 securityManager:安全管理器,主体进行认证和授权都是通过securityManager进行。securityManager是一个集合,
真正做事的不是securityManager而是它里面的东西。
3.3 authenticator:认证器,主体进行认证最终通过authenticator进行的。
3.4 authorizer:授权器,主体进行授权最终通过authorizer进行的。
3.5 sessionManager:web应用中一般是用web容器(中间件tomcat)对session进行管理,shiro也提供一套session管理的方式。
shiro不仅仅可以用于web管理也可以用于cs管理,所以他不用web容器的session管理。
3.6 SessionDao: 通过SessionDao管理session数据,针对个性化的session数据存储需要使用sessionDao
(如果用tomcat管理session就不用SessionDao,如果要分布式的统一管理session就要用到SessionDao)。
3.7 cache Manager:缓存管理器,主要对session和授权数据进行缓存(权限管理框架主要就是对认证和授权进行管理,
session是在服务器缓存中的),比如将授权数据通过cacheManager进行缓存管理,
和ehcache整合对缓存数据进行管理(redis是缓存框架)。
3.8 realm:域,领域,相当于数据源,通过realm存取认证、授权相关数据(原来是通过数据库取的)。
注意:authenticator认证器和authorizer授权器调用realm中存储授权和认证的数据和逻辑。
3.9 cryptography:密码管理,比如md5加密,提供了一套加密/解密的组件,方便开发。比如提供常用的散列、加/解密等功能。比如 md5散列算法(md5只有加密没有解密)。

4. Shiro身份验证(shiro.ini)

http://shiro.apache.org/
https://www.w3cschool.cn/shiro/andc1if0.html

小结:身份验证的步骤
1 收集用户身份 / 凭证,即如用户名 / 密码;
2 调用 Subject.login 进行登录,如果失败将得到相应的 AuthenticationException 异常,根据异常提示用户错误信息;否则登录成功;
3 最后调用 Subject.logout 进行退出操作。

5. Shiro权限认证(支持三种方式的授权)

5.1 编程式:通过写if/else授权代码块完成
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
//有权限
} else {
//无权限
}

5.2 注解式:通过在执行的Java方法上放置相应的注解完成,另外,没有权限将抛出相应的异常
@RequiresRoles(“admin”)
public void hello() {
//有权限
}

5.3 JSP/GSP标签:在JSP/GSP页面通过相应的标签完成


6. 授权

6.1 基于角色的访问控制(shiro-role.ini|粗颗粒度)
规则:“用户名=密码,角色1,角色2”
方法: hasRole/hasRoles/hasAllRoles和checkRole/checkRoles

  注1:hasXxx和checkXxx区别,hasXxx会返回boolean类型的数据,用来判断,而checkXxx不会返回任何东西,
       如果验证成功就继续处理下面的代码,否则会抛出一个异常UnauthorizedException

6.2 基于资源的访问控制(shiro-permission.ini|细颗粒度)
即:首先根据用户名找到角色,然后根据角色再找到权限
规则1:“用户名=密码,角色1,角色2”
规则2:“角色=权限1,权限2”
规则3:“资源标识符:操作:对象实例ID” 即对哪个资源的哪个实例可以进行什么操作
注:每个部分可以不填写,默认就是*
user::
tea::
stu::

  方法: isPermitted/checkPermissions   

  注1:permission:许可,权限
  注2:create,update,delete,view这些是可以自行定义的

7. shiro集成web(shiro-web.ini)

<%@taglib prefix=“r” uri=“http://shiro.apache.org/tags” %>

7.1 配置shiro-web.ini文件

7.2 通过监听器EnvironmentLoaderListener读取配置文件,来创建相应的WebEnvironment

  注1:可通过shiroConfigLocations参数,指定shiro的配置文件
  注2:shiroConfigLocations 默认是“/WEB-INF/shiro.ini”,IniWebEnvironment默认是先从/ WEB-INF/shiro.ini加载,
       如果没有就默认加载 classpath:shiro.ini。

7.3 配置过滤器ShiroFilter

  注1:放在web.xml文件的最前面

7.4 开发中不断修改配置文件

8. 其它

8.1 不足之处
1. 用户名/密码硬编码在ini配置文件,以后需要改成如数据库存储,且密码需要加密存储;
2. 用户身份Token可能不仅仅是用户名/密码,也可能还有其他的,如登录时允许用户名/邮箱/手机号同时登录。
8.2 JUnit4:Test注解的两个属性:expected和timeout
expected属性:用来指示期望抛出的异常类型,抛出指定的异常类型,则测试通过 。
timeout属性:用来指示时间上限,当测试方法的时间超过这个时间值时测试就会失败(注意超时了报的是Errors,如果是值错了是Failures)

9. 配置文件

xml
properties
ini
[node]
key=value

10.shiro认证

shiro原理
1,首先构造securityManager环境。
2, 调用subject.login方法主体提交认证,提交的token。
3,securityManager进行认证,securityManager最终由ModularRealmAuthenticator进行认证。
4,ModularRealmAuthenticator调用IniRealm(给realm传入token)去ini配置文件中查询用户信息
5,IniRealm根据输入的
token(UsernamePasswordToken)从shiro-first.ini查询用户信息,根据账号查询用户信息(账号和密码)
如果查询到用户信息,就给ModularRealmAuthenticator返回用户信息(账号和密码)
如果查询不到,就给ModularRealmAuthenticator返回null
6,ModularRealmAuthenticator接收IniRealm返回Authentication认证信息
如果返回的认证信息是null,ModularRealmAuthenticator抛出异常
Shiro入门_第4张图片
相关代码
创建一个maven项目,导入日志log4j2.xml





    
        
        
        ${sys:user.home}/logs
        ${sys:user.home}/logs/error
        ${sys:user.home}/logs/warn

        
        
        
        
        

        
        %d{yyyy-MM-dd HH:mm:ss.SSS} [%t-%L] %-5level %logger{36} - %msg%n
        
    

    
        
        
            
            
            
            
            
        

        
        
        
            
        
        
        
            
            
            
            
                
                
                
                
                
                
            
        

        
            
            
            
                
                
            
            
            
        

        
            
            
            
                
                
                
            
        

    

    
    
        
        
        
        
        
        
        
        


        
        
            
            
            
            
        
    



导入pom.xml相关依赖



  4.0.0

  com.javachz
  Shiro01
  1.0-SNAPSHOT
  war

  Shiro01 Maven Webapp
  
  http://www.example.com

  
    UTF-8
    1.7
    1.7
    3.7.0

    
    4.12
    4.0.0
    2.9.1
    1.7.7
    3.2.0

    1.2.5
  

  
    
    
      org.apache.shiro
      shiro-core
      ${shiro.version}
    
    
    
      org.apache.shiro
      shiro-web
      ${shiro.version}
    
    
    
      junit
      junit
      ${junit.version}
      test
    
    
    
      javax.servlet
      javax.servlet-api
      ${servlet.version}
      provided
    
    
    
      org.slf4j
      slf4j-api
      ${slf4j.version}
    
    
      org.slf4j
      jcl-over-slf4j
      ${slf4j.version}
      runtime
      
        
          slf4j-api
          org.slf4j
        
      
    
    
    
      org.apache.logging.log4j
      log4j-slf4j-impl
      ${log4j2.version}
      
        
          slf4j-api
          org.slf4j
        
      
    
    
    
      org.apache.logging.log4j
      log4j-api
      ${log4j2.version}
    
    
      org.apache.logging.log4j
      log4j-core
      ${log4j2.version}
    
    
    
      org.apache.logging.log4j
      log4j-web
      ${log4j2.version}
      runtime
    
    
    
      com.lmax
      disruptor
      ${log4j2.disruptor.version}
    

  

  

    Shiro01
    
      
      
        src/main/java
        
          **/*.xml
        
      
      
      
        src/main/resources
        
          *.properties
          *.xml
          *.ini
        
      
    
    
      
        
        
          org.apache.maven.plugins
          maven-compiler-plugin
          ${maven.compiler.plugin.version}
          
            ${maven.compiler.source}
            ${maven.compiler.target}
            ${project.build.sourceEncoding}
          
        


        
          maven-clean-plugin
          3.1.0
        
        
        
          maven-resources-plugin
          3.0.2
        
        
          maven-compiler-plugin
          3.8.0
        
        
          maven-surefire-plugin
          2.22.1
        
        
          maven-war-plugin
          3.2.2
        
        
          maven-install-plugin
          2.5.2
        
        
          maven-deploy-plugin
          2.8.2
        
      
    
  


shiro.ini

[users]
zs=123
ls=456
ww=789

导入web.xml里面相应的配置


  Archetype Created Web Application
  
    shiroConfigLocations
    classpath:shiro-web.ini
  
  
    org.apache.shiro.web.env.EnvironmentLoaderListener
  

  
    ShiroFilter
    org.apache.shiro.web.servlet.ShiroFilter
  
  
    ShiroFilter
    /*
  



ShiroTest.java

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;


/**
 * @author 52hz
 * @site www.javachz.com
 * @company xxx公司
 * @create  2019-11-29 16:50
 *
 * shiro入门
 * 1,将数据源realm读取securityManagerFactoy
 * 2,securityManageractory创建出安全管理器实例securityManager
 * 3,将securityManageractory交给securityUtil
 * 4,securityUtil获取登录主体subject
 * 5,从jsp获取到用户名密码然后将其组装成登录令牌token
 * 6,subject去使用令牌token进行登录
 * 7,登录可能成功,也可能失败,那么需要对登录的结果进行处理
 */
public class ShiroTest {
    public static void main(String[] args) {
        IniSecurityManagerFactory securityManagerFactory=new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = securityManagerFactory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
        Subject subject=SecurityUtils.getSubject();
        String jspUname="zs";
        String jspPwd="123";
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(jspUname, jspPwd);
        //登录出去
//        subject.logout();
        try {
            subject.login(usernamePasswordToken);
            System.out.println("登录成功的业务逻辑");
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("登录失败后的处理代码逻辑");
        }

    }

}

shiro-web.ini

[main]
#定义身份认证失败后的请求url映射,loginUrl是身份认证过滤器中的一个属性
authc.loginUrl=/login
#定义角色认证失败后的请求url映射,unauthorizedUrl是角色认证过滤器中的一个属性
roles.unauthorizedUrl=/unauthorized.jsp
#定义权限认证失败后请求url映射,unauthorizedUrl是角色认证过滤器中的一个属性
perms.unauthorizedUrl=/unauthorized.jsp

[users]
zs=123,role1
ls=123,role2
ww=123,role3
zdm=123,admin


[roles]
role1=user:create
role2=user:create,user:update
role3=user:create,user:update,user:delete,user:view,user:load
admin=user:*



#定义请求的地址需要做什么验证
[urls]
#请求login的时候不需要权限,游客身份即可(anon)
/login.do=anon

#请求/user/updatePwd.jsp的时候,需要身份认证(authc)
/user/updatePwd.jsp=authc

#请求/admin的时候,需要角色认证,必须是拥有admin角色的用户才行
/admin/*.jsp=roles[admin]

#请求/teacher的时候,需要权限认证,必须是拥有user:create权限的角色的用户才行
/user/teacher.jsp=perms["user:update"]

LoginServlet.java

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author 52hz
 * @site www.javachz.com
 * @company xxx公司
 * @create  2019-11-29 18:16
 */
public class LoginServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Subject subject= SecurityUtils.getSubject();
        String jspUname=req.getParameter("username");
        String jspPwd=req.getParameter("password");
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(jspUname, jspPwd);
        //登录出去
//        subject.logout();
        try {
            subject.login(usernamePasswordToken);
            System.out.println("登录成功的业务逻辑");
            req.getSession().setAttribute("username",jspUname);
            req.getRequestDispatcher("/main.jsp").forward(req,resp);
        }catch (Exception e){
            e.printStackTrace();
//            System.out.println("登录失败后的处理代码逻辑");
            req.getSession().setAttribute("message","用户或者密码错误!!!");
            req.getRequestDispatcher("/login.jsp").forward(req,resp);
        }

    }


}

loginoutServlet.java

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author 52hz
 * @site www.javachz.com
 * @company xxx公司
 * @create  2019-11-29 18:25
 */
@WebServlet("/logout")
public class loginoutServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Subject subject=SecurityUtils.getSubject();
        subject.logout();
        resp.sendRedirect("/login.jsp");
    }
}

准备相应的jsp页面,这里就不多介绍了,看效果图

Shiro入门_第5张图片
Shiro入门_第6张图片

你可能感兴趣的:(Shiro,学习中)