shiro中文api_Shiro

shiro中文api_Shiro

1 shiro

Apache shiro 是一个 Java 安全框架。

功能:认证、授权、加密和会话管理功能

应用环境:JavaEE、JavaSE

shiro中文api_Shiro

Subject 可看做成一个用户

SecurityManager 框架的核心API

Reaim 域对象,用于取数据库中的数据,进行权限比对。

shiro中文api_Shiro

| 名词 | 名词中文解释 | | -------------- | ------------ | | Subject | 主体 | | Security | 安全 | | Realm | 领域、范围 | | Authenticator | 认证器 | | Authentication | 认证 | | Authorizer | 授权器 | | Authorization | 授权 | | Cryptography | 密码、凭证 | | Credential | 证书、凭证 | | Matcher | 匹配器 | | Principal | 身份 |

shiro 配置文件

shiro.ini 文件放在 claspath 中,shiro会自动查找。其中格式是key/value键值对配置。

Ini 配置文件一般适合与用户少且不需要在运行时动态创建的情景下使用。

ini 配置文件有四大类:main,users,roles,urls

[main]

main 主要配置shiro 的一些对象,例如:securityManager,Realm,authenticator,authcStrategy

[users]

作用:配置一组静态的用户

格式:key:value ,key表示密码的名字,value 表示密码的值

zeros=1233

[roles]

作用:将角色和权限关联操作

格式:资源:操作

role1= printer:create,printer:query

[urls]

作用:拦截对应的 URL 请求。

2 实现简单认证

认证:验证用户是否合法。

2.1 实现步骤

导入 jar 包

junit-4.9.jar log4j-1.2.17.jar shiro-all-1.3.2.jar slf4j-api-1.7.5.jar slf4j-log4j12-1.7.5.jar

编写 shiro.ini 配置文件

[users]zeros=1233

测试

package com.szxy.shiro;
 
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;
import org.junit.Test;
 
public class SampleAuthentication {
    @Test
    public void sampleAuthentication(){
        //构建  SecurityManagerFactory 工厂
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory();
        //利用 SecurityManagerFactory 实例化  SecurityManager 对象
        SecurityManager securityManager = factory.getInstance();
        // 将 SecurityManager 设置到运行环境中
        SecurityUtils.setSecurityManager(securityManager);
        //通过SecurityUtils, 创建主体 Subject
        Subject subject = SecurityUtils.getSubject();
        //创建用户密码令牌认证
        UsernamePasswordToken token = new UsernamePasswordToken("admin1","passwd");
        //验证身份
        subject.login(token);
        //查看结果
        System.out.println(subject.isAuthenticated());
    }
}

3 Realm 域

shiro 默认使用 IniRealm 源,默认从 init 配置文件中读取用户信息。

3.1 实现步骤

建立 users 表

注意:表名必须是 users 。jdbcRealm 查找数据库中的表就是 users 表。

导入 jar 包

com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar commons-beanutils-1.9.2.jar commons-logging-1.1.1.jar junit-4.9.jar log4j-1.2.17.jar mysql-connector-java-5.1.30.jar shiro-all-1.3.2.jar slf4j-api-1.7.5.jar slf4j-log4j12-1.7.5.jar

编写 shiro.ini 配置文件

[main]
#配置Realm
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
#配置数据源
dataSource = com.mchange.v2.c3p0.ComboPooledDataSource
dataSource.driverClass = com.mysql.jdbc.Driver
dataSource.jdbcUrl = jdbc:mysql:///rbac
dataSource.user = root
dataSource.password = root
 
jdbcRealm.dataSource = $dataSource
 
#将 Realm 注入给 SecurityManager
securityManager.realm = $jdbcRealm

测试

同简单认证的测试方法

4 自定义 Realm

好处:可以给 securityManager 更加灵活的安全数据源(eg。jdbcRealm 中表和字段都限定了)

方式:通过实现 Realm 接口,或根据需要继承他的响应子类即可。 AuthenticatingRealm

需求: 使用自定义 Realm ,从而实现认证。

实现步骤

导入 jar 包

com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar commons-beanutils-1.9.2.jar commons-logging-1.1.1.jar junit-4.9.jar log4j-1.2.17.jar mysql-connector-java-5.1.30.jar shiro-all-1.3.2.jar slf4j-api-1.7.5.jar slf4j-log4j12-1.7.5.jar

编写自定义 Realm

package com.szxy.realm;
 
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
 
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.subject.PrincipalCollection;
 
import com.mysql.jdbc.Driver;
 
 
public class CustRealm extends  AuthenticatingRealm {
 
    private String principals; //用户名
    private String credentials;    //密码
    private String driverName = "com.mysql.jdbc.Driver";
    private String url = "jdbc:mysql:///rbac";
    private String user = "root";
    private String password = "root";
 
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
            // 使用 jdbc 连接数据库
            Connection conn = null;
            Statement stat = null;
            ResultSet rs = null;
            try {
                //注册驱动
                /*Driver driver = new Driver();
                DriverManager.registerDriver(driver);*/
                Class.forName(driverName);
                //获取数据库连接
                conn =  DriverManager.getConnection(url, user, password);
                //操作数据库对象
                stat = conn.createStatement();
                //定义 sql 语句
                String sql  = "select username,password from users";
                //执行 查询语句
                rs = stat.executeQuery(sql);
                //获取 结果集
                if(rs.next()){
                    principals = rs.getString("username");
                    credentials = rs.getString("password");
                }
            } catch (SQLException | ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }finally{
                if(rs!=null){
                    try {
                        rs.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                if(stat!=null){
                    try {
                        stat.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                if(conn !=null){
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
 
            //创建 AuthenticationInfo 接口 实现类
            SimpleAuthenticationInfo info =
                    new SimpleAuthenticationInfo(principals, credentials,"custRealm");
            return info;
    }
}

编写 shiro.ini 配置文件

[main]
#配置Realm
custRealm = com.szxy.realm.CustRealm
 
#将 Realm 注入给 SecurityManager
securityManager.realm = $custRealm

测试

同上测试

5 加密方式

对称加密算法

加密的密钥与解密的密钥相同

shiro中文api_Shiro

非对称算法算法

加密的密钥与解密的密钥不相同

公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。

公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。

shiro中文api_Shiro

对称与非对称算法

shiro中文api_Shiro

散列算法比较

MD5加密、加盐与迭代

加盐

原因:相同的 password 生产相同的 Hash 值是相同

原理:给原文加入随机数生成新的MD5

加盐 salt:指往原文加入的随机数

迭代

加密的次数

| Md5Hash的构造方法 | 参数名用法 | | ------------------------------------------------------------ | ----------------------- | | public Md5Hash(Object source) | source指加密的数据 | | public Md5Hash(Object source, Object salt) | salt 加盐 | | public Md5Hash(Object source, Object salt, int hashIterations) | hashIterations 迭代次数 | | public Md5Hash() | 无参构造器 |

代码示例

package com.szxy.md5;
 
import org.apache.shiro.crypto.hash.Md5Hash;
 
public class TestMd5 {
 
    public static void main(String[] args) {
        //直接加密  
        Md5Hash md5 = new Md5Hash("123");
        System.out.println(md5);//202cb962ac59075b964b07152d234b70
        //加盐 salt 
        md5 = new Md5Hash("123", "zwz");
        System.out.println(md5); //3b52ecfc4719fcb6c863208063548792
        //迭代,即加密的次数
        md5 = new Md5Hash("123", "zwz", 2);
        System.out.println(md5); //de231265fe7ec45af1404ded2f365001 
    }
}

6 凭证匹配器 Authentication

AuthenticatingRealm

修改 realm

//ByteSource.Utilbytes(salt)
package com.szxy.realm;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
 
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.util.ByteSource;
 
 
public class CustRealm extends  AuthenticatingRealm{
 
    private String principals; //用户名
    private String credentials;    //密码
    private String driverName = "com.mysql.jdbc.Driver";
    private String url = "jdbc:mysql:///shiro";
    private String user = "root";
    private String password = "root";
    private String salt = null;   //加盐的盐值
 
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
            // 使用 jdbc 连接数据库
            Connection conn = null;
            Statement stat = null;
            ResultSet rs = null;
            try {
                //注册驱动
                /*Driver driver = new Driver();
                DriverManager.registerDriver(driver);*/
                Class.forName(driverName);
                //获取数据库连接
                conn =  DriverManager.getConnection(url, user, password);
                //操作数据库对象
                stat = conn.createStatement();
                //定义 sql 语句
                String sql  = "select username,password,salt from starUsers";
                //执行 查询语句
                rs = stat.executeQuery(sql);
                //获取 结果集
                if(rs.next()){
                    principals = rs.getString("username");
                    credentials = rs.getString("password");
                    salt  = rs.getString("salt");
                }
            } catch (SQLException | ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }finally{
                if(rs!=null){
                    try {
                        rs.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                if(stat!=null){
                    try {
                        stat.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                if(conn !=null){
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
 
            ByteSource byteSource = ByteSource.Util.bytes(salt); //加盐
            //创建 AuthenticationInfo 接口 实现类
            SimpleAuthenticationInfo info =
                    new SimpleAuthenticationInfo(principals, credentials,byteSource,"customRealm");
            return info;
    }
}

配置 shiro 配置文件

[main]
 
#配置凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
 
#设置凭证匹配器的相关属性
credentialsMatcher.hashAlgorithmName=MD5
credentialsMatcher.hashIterations=2
 
#配置Realm
customRealm=com.szxy.realm.CustRealm
 
#配置Realm的凭证匹配器属性
customRealm.credentialsMatcher=$credentialsMatcher
 
#将Realm注入给SecurityManager
securityManager.realm=$customRealm

7 授权 Authorization

授权,又称访问控制,是对资源访问管理的过程。
即对于认证通过的用户,授予他可以访问某些资源的权限

授权方式

代码触发、注解触发、标签触发

授权流程图

shiro中文api_Shiro

配置文件

[main]
 
#配置凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
 
#设置凭证匹配器的相关属性
credentialsMatcher.hashAlgorithmName=MD5
credentialsMatcher.hashIterations=2
 
#配置Realm
customRealm=com.szxy.realm.CustRealm
 
#配置Realm的凭证匹配器属性
customRealm.credentialsMatcher=$credentialsMatcher
 
#将Realm注入给SecurityManager
securityManager.realm=$customRealm

代码示例

package com.szxy.realm;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
 
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
 
 
public class CustRealm extends  AuthorizingRealm{
 
    private String principals; //用户名
    private String credentials;    //密码
    private String driverName = "com.mysql.jdbc.Driver";
    private String url = "jdbc:mysql:///shiro";
    private String user = "root";
    private String password = "root";
    private String salt = null;   //加盐的盐值
 
    private String roleName;  //角色名称
    private String remark;
 
    // 验证的方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
            // 使用 jdbc 连接数据库
            Connection conn = null;
            Statement stat = null;
            ResultSet rs = null;
            try {
                //注册驱动
                /*Driver driver = new Driver();
                DriverManager.registerDriver(driver);*/
                Class.forName(driverName);
                //获取数据库连接
                conn =  DriverManager.getConnection(url, user, password);
                //操作数据库对象
                stat = conn.createStatement();
                //定义 sql 语句
                String sql  = "select username,password,salt from starUsers";
                //执行 查询语句
                rs = stat.executeQuery(sql);
                //获取 结果集
                if(rs.next()){
                    principals = rs.getString("username");
                    credentials = rs.getString("password");
                    salt  = rs.getString("salt");
                }
            } catch (SQLException | ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }finally{
                if(rs!=null){
                    try {
                        rs.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                if(stat!=null){
                    try {
                        stat.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                if(conn !=null){
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
 
            ByteSource byteSource = ByteSource.Util.bytes(salt); //加盐
            //创建 AuthenticationInfo 接口 实现类
            SimpleAuthenticationInfo info =
                    new SimpleAuthenticationInfo(principals, credentials,byteSource,"customRealm");
            return info;
    }
 
    // 授权的方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        // 使用 jdbc 连接数据库
        Connection conn = null;
        Statement stat = null;
        ResultSet rs = null;
        try {
            //注册驱动
            /*Driver driver = new Driver();
            DriverManager.registerDriver(driver);*/
            Class.forName(driverName);
            //获取数据库连接
            conn =  DriverManager.getConnection(url, user, password);
            //操作数据库对象
            stat = conn.createStatement();
            //定义 sql 语句
            //String sql  = "select rolename from roles";
            String  sql = "select * from permission"; 
            //执行 查询语句
            rs = stat.executeQuery(sql);
            //获取 结果集
            if(rs.next()){
                //roleName = rs.getString("rolename");
                remark = rs.getString("remark");
            }
        } catch (SQLException | ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            if(rs!=null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if(stat!=null){
                try {
                    stat.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if(conn !=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();   
        //info.addRole(roleName);         //添加角色信息
        info.addStringPermission(remark); //添加权限信息
        return info;
    }
}

测试

package com.szxy.shiro;
 
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
 
public class TestShiro {
    @Test
    public void TestAuthorization(){
        //构建  SecurityManagerFactory 工厂
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory();
        //利用 SecurityManagerFactory 实例化  SecurityManager 对象
        SecurityManager securityManager = factory.getInstance();
        // 将 SecurityManager 设置到运行环境中
        SecurityUtils.setSecurityManager(securityManager);
        //通过SecurityUtils, 创建主体 Subject
        Subject subject = SecurityUtils.getSubject();
        //创建用户密码令牌认证
        UsernamePasswordToken token = new UsernamePasswordToken("admin","123");
        //验证身份
        subject.login(token);
        //查看结果
        System.out.println(subject.isAuthenticated());
 
        //验证权限
        //基于角色授权
        boolean flag = subject.hasRole("管理员1");
        System.out.println(flag);
        //权限授权
        boolean flag2 = subject.isPermitted("一级菜单,基本设置操作权限");
        System.out.println(flag2);
 
    }
 
}

8 spring 整合Shiro

新建项目,导入 jar 包

编写配置文件

编写 web.xml

DelegatingFilterProxy

通过代理模式将 servlet 容器中 filter 同 spring 容器的 bean 关联起来

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>RBACDemo</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <!-- 监听 ServletContext ,注册  Spring 容器 -->
  <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <!-- 指定 spring 配置文件的名称及位置 -->
  <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext-*.xml</param-value>
  </context-param>
 
  <!-- 注册 SpringMVC 容器 -->
  <servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class> org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 指定 SpringMVC 配置文件的位置 -->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:SpringMVC.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
 
  <!-- 开启编码过滤器 -->
  <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
 
  <!-- 注册 DelegatingFilterProxy 
          通过代理模式将 servlet 容器中 filter 同 spring 容器的 bean 关联起来
    -->
  <filter>
    <filter-name>delegatingFilterProxy</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <!--
        该属性为 true 表名启用引用 filter 的init() 和 destroy() 
    -->
    <init-param>
        <param-name>targetFilterLifecycle</param-name>
        <param-value>true</param-value>
    </init-param>
    <!--
        该属性设置 spring 容器中 filter 的bean的 id
    -->
    <init-param>
        <param-name>targetBeanName</param-name>
        <param-value>shiroFilter</param-value>
    </init-param>   
  </filter>
  <filter-mapping>
    <filter-name>delegatingFilterProxy</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

spring-shiro.xml

<!-- 注册凭证匹配器,并为其注入属性值-->
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
    <!-- 加密方式 -->
    <property name="hashAlgorithmName" value="md5"></property>
    <!-- 迭代次数 -->
    <property name="hashIterations" value="2" ></property>
</bean>
 
<!-- 注册自定义 realm  -->
<bean id="customRealm" class="com.szxy.realm.CustomRealm">
    <property name="credentialsMatcher" ref="credentialsMatcher"></property>
</bean>
 
<!-- 注册 SecurityManager  -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realm" ref="customRealm"></property>
</bean>
 
<!--
   注册 shiroFilterFactoryBean 
   注意:bean 的id 名称必须与过滤器中的名称一致
   -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager"></property>
    <property name="loginUrl" value="/login.do"></property>
    <property name="successUrl" value="/jsp/users.jsp"></property>
    <property name="unauthorizedUrl" value="/jsp/refuse.jsp"></property>
    <!-- 设置过滤器链属性 -->
    <property name="filterChainDefinitions">
        <value>
            /login.do=authc
            /**=anon
        </value>
    </property>
</bean>

代码示例

9 DelegatingFilterProxy

DelegatingFilterProxy 源码分析

void initFilterBean() 初始化过滤器 bean 对象,并调用 Filter initDelegate(WebApplicationContext wac) 方法,

从 spring 容器取出 目标 target 的bean 对象,并对其他进行初始化操作。

@Override
protected void initFilterBean() throws ServletException {
    synchronized (this.delegateMonitor) {
        if (this.delegate == null) {
            // If no target bean name specified, use filter name.
            if (this.targetBeanName == null) {
                this.targetBeanName = getFilterName();
            }
            // Fetch Spring root application context and initialize the delegate early,
            // if possible. If the root application context will be started after this
            // filter proxy, we'll have to resort to lazy initialization.
            WebApplicationContext wac = findWebApplicationContext();
            if (wac != null) {
                this.delegate = initDelegate(wac); 
            }
        }
    }
 
//Initialize the Filter delegate, defined as bean the given Spring
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
        Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
        if (isTargetFilterLifecycle()) {
            //该属性为 true 表名启用引用 filter 的init() 和 destroy() 交给 spring 容器管理 
            delegate.init(getFilterConfig());
        }
        return delegate;
}

10 spring 整合 Shiro 之注册

密码使用 md5 方式加密

表单序列化

使用该操作,可以直接获取表单数据,简化操作。

<script type="text/javascript" src="js/jquery-1.7.2.min.js"></script>
    <script type="text/javascript" >
        $(function(){
            $("#btn").click(function(){
                $.ajax({
                    url:"/user/register",
                    type:"POST",
                    data:$("#myForm").serialize(),//表单序列化,传递表单数据
                    success:function(data){
                        alert(data);
                    }
                });
            });
        });
</script>

md5加密

@Override
public int userRegister(User user) {
    //使用 md5 加密用户的密码,并使用用户名作为 salt 值
    Md5Hash newPassword = 
        new Md5Hash(user.getPassword(),user.getUsername(), 2);
    user.setPassword(newPassword.toString());
    user.setSalt(user.getUsername());
    return userMapper.insertUser(user);
}

9 实现菜单授权

11 SessionMapper 的使用

sessionMamanager 会话管理器管理着应用中所有的 Subject 的会话的创建、维护、删除、失效、验证等工作。

Shiro 提供了三个默认实现类:

| 类名 | 功能 | | ------------------------------ | ------------------------------------------------------------ | | DefaultSessionManager | 用于 JavaSE 环境 | | ServletContainerSessionManager | 用于 Web 环境,直接使用 tomcat 容器管理对象 | | DefaultWebSessionManager | 用于Web 环境,替代 类名功能DefaultSessionManager用于 JavaSE 环境ServletContainerSessionManager,自己维护会话。 |

<!-- 注册 sessionManager  -->
<bean id="sessionManager" class="org.apache.shiro.session.mgt.DefaultSessionManager">
    <!-- 设置 session 超时时间  ,以毫秒为单位 ms   1s 等于 1000ms -->
    <property name="globalSessionTimeout" value="500000"></property>
    <property name="deleteInvalidSessions" value="true"></property>
</bean>

12 remeber me 功能实现

即登录成功后,下次免登录

实现步骤

用户类即及其引用类的都需要序列化

修改页面 index .jsp

修改 Spring-shiro.xml

13 Shiro 内置过滤器

1 认证过滤器

anon authcBasic auchc user

2 授权过滤器

perms roles ssl rest port

shiro中文api_Shiro

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager"></property>
    <property name="loginUrl" value="/user/login.do"></property>
    <property name="successUrl" value="/user/loginSuccess.do"></property>
    <property name="unauthorizedUrl" value="/jsp/refuse.jsp"></property>
    <!-- 设置过滤器链属性 
       authc 认证过滤器,表示表单认证
       anon  放行,可以匿名访问,不需要认证
       user  用户过滤器,用于识别当前用户是否登录并保存密码  RememberMe
     -->
    <property name="filterChainDefinitions">
        <value>
            /user/login.do=authc 
            /user/loginSuccess.do=user
            /menu/showMenu.do=user
            /**=anon
        </value>
    </property>
</bean>

注意

使用 Shiro 框架做用户登录的时候,若登录成功后,在使用浏览器回来之前的登录界面,这时就登录不上了,不仅是使用之前登录的账号,还是其他账号。

推测:可能是同一 浏览器登录后存在 cookie ,影响用户的二次登录。

上一篇:Dubbo 同步、异步调用的几种方式


下一篇:Shiro入门