zoukankan      html  css  js  c++  java
  • 在Web项目中使用shiro

    1.先导入所需要的依赖包

    2.【shiro-web】依赖库引用完成之后,需要修改web.xml配置文件

      • 进行shiro整合一定要在web.xml配置文件中配置一个Shiro环境监听器

      • 在任何一个shiro项目里面都睡存在有一个shiro.ini配置文件,需要在web.xml配置文件中为其追加一个配置的过滤器

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                          http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
      <listener><!--shiro环境监听器-->
        <listener-class>
          org.apache.shiro.web.env.EnvironmentLoaderListener
        </listener-class>
      </listener>
      <filter><!--过滤shiro.ini配置文件-->
        <filter-name>ShiroFilter</filter-name>
        <filter-class>
          org.apache.shiro.web.servlet.ShiroFilter
        </filter-class>
        <init-param>
          <param-name>configPath</param-name>
          <param-value>classpath:shiro.ini</param-value>
        </init-param>
      </filter>
      <filter-mapping>
        <filter-name>ShiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
        <dispatcher>ERROR</dispatcher>
      </filter-mapping>
    </web-app>
    

    3.src/main/resources/目录下的shiro.ini配置文件:ini文件中主要配置有四大类:main,users,roles,urls

      ● main:配置shiro对象,例如securityManager,Realm,authenticator,autchStrategy等等

      ● users:配置静态的用户信息,包含用户名,密码,角色,一个用户可以拥有多个角色。如:lee=hello,member,dept  其中lee为用户名,hello为密码,member和dept为角色

      ● roles:定义角色与权限的关联。如:member=member:add,member:list,member:edit  其中代表着member角色下的add,list和edit权限

      ● urls:配置主要在web应用中,格式为:url=拦截器[参数],拦截器[参数],...。如:/login.jsp=anon

    4.自定义Realm:

      ● 自定义Realm一定要实现Realm接口并覆写其中的三个方法,例如以下代码

    package com.yootk.shiro.realm;
    
    import org.apache.shiro.authc.*;
    import org.apache.shiro.realm.Realm;
    
    public class MyselfDefaultRealm implements Realm {
        private static int count = 0 ;
        @Override
        public String getName() {   // 获取Realm的名称
            return "my-happy-realm - " + count++;
        }
    
        @Override
        public boolean supports(AuthenticationToken token) {    // 判断当前的Token是否可以使用此Realm
            return token instanceof UsernamePasswordToken; // 当前Realm只支持“UsernamePasswordToken”类型
        }
    
        @Override
        public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            String mid = (String) token.getPrincipal() ;    // 获取用户名
            String password = new String((char[]) token.getCredentials()) ; // 获取密码
            if (!"lee".equals(mid)) {   // 此时用户名不存在
                throw new UnknownAccountException("【"+mid+"】该用户信息不存在,请确认输入的用户名!") ;
            }
            if (!"hello".equals(mid)) { // 密码不正确
                throw new IncorrectCredentialsException("错误的用户名或密码!") ;
            }
            return new SimpleAuthenticationInfo(token.getPrincipal(),token.getCredentials(),this.getName()) ;
        }
    }
    

      ● 编写完自定义Ream类之后需要在shiro.ini配置文件中配置一下

    [main]
    #要想让自定义的Realm生效一定要配置这两项 # 将自定义的Realm定义在配置文件之中,表示此类的对象将由Shiro类负责实例化 myselfRealm=com.yootk.shiro.realm.MyselfDefaultRealm # 此时的配置就表示调用了SecurityManager子类中的setRealms()方法进行设置,内部引用使用“$”符号 securityManager.realms=$myselfRealm [urls] #web项目一定要设置过滤链,否则会报缺少FilterChainResolver /login.jsp=anon

    5.配置JDBC认证信息,系统里面不仅仅只包含有自定义Realm,同时还提供有一种JdbcRealm程序,这类程序的最大特点是可以直接进行数据库的认证信息。

      ● 想使用JdbcRealm,首先需要修改pom.xml配置文件引入mysql-connector-java依赖包

      ● 修改shiro.ini配置文件,引入JdbcRealm进行程序的处理

    [main]
    # 定义当前项目之中要使用的DataSource,此时的DataSource为MySQL驱动自带
    dataSource=com.mysql.jdbc.jdbc2.optional.MysqlDataSource
    #dataSource.url=jdbc:mysql://localhost:3306/yootk_authentication
    dataSource.serverName=localhost
    dataSource.port=3306
    dataSource.databaseName=yootk_authentication
    dataSource.user=root
    dataSource.password=mysqladmin
    # 定义JdbcRealm类型,为当前的使用Realm
    jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
    # 为JdbcRealm设置要使用的数据源
    jdbcRealm.dataSource=$dataSource
    # 设置数据库的查询操作指令
    jdbcRealm.authenticationQuery=SELECT password FROM member WHERE mid=? AND locked=0
    # 将当前使用的Realm整合在SecurityManager之中
    securityManager.realms=$jdbcRealm
    [urls]
    /login.jsp=anon

    6.Realm与Subject与token与SececurityManager与SecurityUtils的关系

      ● 首先创建一个SececurityManager的实例

      ● Realm设置数据源,读取shiro.ini文件

      ● SececurityManager的实例设置上具体的Realm对象

      ● SecurityUtils设置上SececurityManager的实例

      ● 通过SecurityUtils.getSubect获得Subject的对象

      ● 实例化对象token并向token中存入用户名和密码

      ● 采用subject.login(token)认证

    package com.yootk.test;
    
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.config.IniSecurityManagerFactory;
    import org.apache.shiro.mgt.DefaultSecurityManager;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.realm.Realm;
    import org.apache.shiro.realm.text.IniRealm;
    import org.apache.shiro.subject.Subject;
    import org.apache.shiro.util.Factory;
    import org.junit.Test;
    
    public class TestShiroBase {
        public static final String USERNAME = "lee" ;   // 假设此处内容为输入数据
        public static final String PASSWORD = "hello" ;  // 假设此处内容为输入数据
        @Test
        public void testAuth() throws Exception {
    
            // 1、创建一个SececurityManager接口类的对象实例,使用子类为了设置realm
            DefaultSecurityManager securityManager = new DefaultSecurityManager() ;
            // 2、所有的认证信息都保存在shiro.ini文件,这个文件存储在CLASSPATH目录下;
            Realm realm = new IniRealm("classpath:shiro.ini") ;
            // 3、此时的SecurityManager需要设置上具体的realm对象信息
            securityManager.setRealm(realm);
            // 4、如果要想进行数据的认证处理,还需要获取SecurityUtils工具类
            SecurityUtils.setSecurityManager(securityManager); // 设置安全管理类实例
            // 5、如果要继续用户认证处理,则首先一定要获取一个Subject(用户)
            Subject subject = SecurityUtils.getSubject();
            // 6、利用一个专属的认证Token的结构包装输入的用户名与密码信息
            AuthenticationToken token = new UsernamePasswordToken(USERNAME,PASSWORD) ;
            // 7、利用Subject实现最终的用户认证处理操作
            subject.login(token); // 进行认证操作
            System.out.println("用户名:" + subject.getPrincipal());
        }
    }
    

    7.以后开发的时候编写自定义Realm类的时候一般会继承AuthorizingRealm类,然后覆写其中的认证和授权方法。

      ● 认证方法是doGetAuthenticationInfo():参数类型.getPrincipal()是获取用户名,参数类型.getCredentials()是获取密码,返回值类型是new SimpleAuthenticationInfo(token.getPrincipal(),token.getCredentials(),this.getName());

      ● 授权方法是doGetAuthorizationInfo():SimpleAuthorizationInfo authz = new SimpleAuthorizationInfo() ; // 返回的授权信息  ;authz.setRoles(map.get("allRoles"));//设置角色;authz.setStringPermissions(map.get("allActions"));//设置权限;return authz;//返回对象

    package com.yootk.shiro.realm;
    
    import com.yootk.shiro.service.IMemberService;
    import com.yootk.shiro.service.impl.MemberServiceImpl;
    import com.yootk.shiro.vo.Member;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    
    // 实现用户认证与授权处理的操作
    public class MemberRealm extends AuthorizingRealm {
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            // 本处的程序要进行用户认证的处理操作
            System.out.println("【MemberRealm】============== 用户认证处理 ==============");
            String mid = (String) token.getPrincipal() ;
            IMemberService memberService = new MemberServiceImpl() ; // 获取业务层接口实例
            Member member = memberService.get(mid) ; // 根据mid查询用户信息
            if (member == null) {   // 用户信息不存在
                throw new UnknownAccountException(mid + "账户信息不存在!") ;
            }
            String password = new String((char[]) token.getCredentials()) ;
            if (!member.getPassword().equals(password)) {   // 密码不同
                throw new IncorrectCredentialsException("错误的用户名或密码!");
            }
            if (member.getLocked().equals(1)) { // 用户锁定了
                throw new LockedAccountException(mid + "账户已经被锁定!");
            }
            return new SimpleAuthenticationInfo(token.getPrincipal(),token.getCredentials(),this.getName());
        }
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            System.out.println("【MemberRealm】============== 用户授权处理 ==============");
            return null;
        }
    
    }
    

    8.Shiro页面标签,修改welcome.jsp,采用shiro.jsp标签来进行控制

      ● 采用标签输出用户名:

    <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %><!--首先要导入此标签-->
    <h1>用户登录成功,欢迎“<shiro:principal/>”光临"</h1>
    

      ● 在用户登录界面上,根据用户是否登录过来进行表单是否显示的判断,采用如下标签用来判断用户的登录状态:

    <shiro:authenticated>
        <h3>您已经登录过了!</h3>
    </shiro:authenticated>

     <shiro:notAuthenticated>
        <h3>您还未登录,显示登录表单!</h3>
       </shiro:notAuthenticated>

      ● 进行用户授权的检测处理:

    <shiro:hasPermission name="member:add">
        <h3>当前用户拥有“member:add”的权限!</h3>
    </shiro:hasPermission>
    

    9.路径访问策略:

      ● 下面这些属性对应的都是后面配置文件中的拦截器

        ● anon 允许匿名访问,不登录也可以访问

        ● authc 认证用户可以访问

        ● logout 注销访问

        ● noSessionCreation 第一次允许访问(如果没有session可以访问,如果有session可以访问)

        ● perms 权限检测访问

        ● roles 角色检测访问

        ● ssl ssl访问,检测http协议

        ● user RememberMe用户访问

        例如下面的shiro.ini文件:

    [main]
    # 将自定义的Realm直接出现在当前的程序之中
    memberRealm=com.yootk.shiro.realm.MemberRealm
    # 将当前使用的Realm整合在SecurityManager之中
    securityManager.realms=$memberRealm
    # 当路径检测失败的时候,应该跳转到登录页面,此处设置登录页面路径
    shiro.loginUrl=/login.jsp
    [users]
    admin=hello,member,dept
    lee=hello,member
    [roles]
    member=member:add,member:list,member:edit
    dept=dept:add,dept:list,dept:edit
    [urls]
    /login.jsp=anon
    /pages/**=authc,roles[member],perms["member:add"]

      ● 如果要想使用这些进行访问处理,那么还需要进行一些良好的路径匹配,就可以使用以下通配符:

        ● "?":匹配任意的0个或1个的内容,例如:"/pages?"表示"/pages1","/pages2"匹配

        ● "*":匹配任意的0个,1个或多个内容,例如:"/pages*"表示"/pages","/pageslee"都可以匹配

        ● "**":匹配任意级的目录,例如:"/pages/**"表示匹配"/pages/"下的所有路径,如:/pages/**=authc

      ● 除了路径匹配之外,也可以进行角色或权限的匹配:

        如:/pages/**=authc,roles[member],perms["member:add"]

  • 相关阅读:
    3月1日起执行!江苏居民阶梯电价有变化!
    个体工商户需要报税吗?
    西红柿的选购方法
    正常人一天该走六千还是一万步?步数滚蛋,运动强度和时长才重要,锻炼身体,快走
    NAT四种类型以及提高NAT类型的途径和方法 nat1 nat2 nat3 nat4
    6种沙坦类药物有什么区别, 选哪一种更好? 药师一次说清楚
    心脏神经官能症是什么症状
    呼吸性碱中毒
    Python Serverless 开源框架:Zappa(详细教程)
    不用代码趣讲 ZooKeeper 集群
  • 原文地址:https://www.cnblogs.com/wxl123/p/11161483.html
Copyright © 2011-2022 走看看