zoukankan      html  css  js  c++  java
  • Shiro的登录验证及授权多Realm情况【基于SpringMVC框架下】

    package com.shiro.action;
    
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.subject.Subject;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    
    @Controller
    public class LoginAction {
        @RequestMapping("/login")
         public String login(@RequestParam("username") String username,
                  @RequestParam("password")String password){
             //创建subject实例
             Subject subject = SecurityUtils.getSubject();
             //判断当前用户是否登录
             if(subject.isAuthenticated()==false){
                 //将用户名及密码封装交个UsernamePasswordToken
                 UsernamePasswordToken token = new UsernamePasswordToken(username,password);
                 try {
                    subject.login(token);
                } catch (AuthenticationException e) {
                    System.out.println("验证不通过,无法登录!");
                    return "error";
                }
             }
            return "success";
             
         }
    }
    package com.shiro.bean;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.HashSet;
    import java.util.Set;
    
    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.authc.UsernamePasswordToken;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.crypto.hash.SimpleHash;
    import org.apache.shiro.realm.jdbc.JdbcRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.util.ByteSource;
    import org.apache.shiro.util.JdbcUtils;
    
    /**
     * @author layne Action方法中执行subject.login(token)时会通过IOC容器调取Realm域进行数据和前端数据比对
     */
    //public class ShiroRealm extends  AuthorizingRealm {

    public class SecondRealm extends JdbcRealm {
    /**
         * Returns all principals associated with the corresponding Subject. Each
         * principal is an identifying piece of information useful to the
         * application such as a username, or user id, a given name, etc - anything
         * useful to the application to identify the current <code>Subject</code>.
         * The returned PrincipalCollection should <em>not</em> contain any
         * credentials used to verify principals, such as passwords, private keys,
         * etc. Those should be instead returned by {@link #getCredentials()
         * getCredentials()}.
         * 
         * @return all principals associated with the corresponding Subject.
         * 
         *         doGetAuthenticationInfo,获取认证消息,如果数据库没有数据,返回null.
         *         AuthenticationInfo可以使用 SimpleAuthenticationInfo实现类,封装给正确用户名和密码
         *         token参数:需要验证的token
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(
                AuthenticationToken token) throws AuthenticationException {
            /**
             * 1.将token转换为UsernamePasswordToken 2.获取用户名 3.查询数据库,进行验证 4.结果返回
             * 5.验证不通过,抛出异常
             */
            // 1.将token转换为UsernamePasswordToken
            UsernamePasswordToken upToken = (UsernamePasswordToken) token;
            // 2.获取用户名
            String userName = upToken.getUsername();
            // 获取用户名后。通过查询用户名查询数据库是否有值,有值则进行密码验证。
            
            SimpleAuthenticationInfo info = null;
            Connection conn=null;
            PreparedStatement ps =null;
            ResultSet rs =null;
            // 3。查询数据库
            // 使用JDBC链接数据库进行查询
            try {
                /*Class.forName("com.mysql.jdbc.Driver");
                String url = "jdbc:mysql://localhost:3306/test";
                Connection conn = DriverManager.getConnection(url, "root", "");*/
                conn= dataSource.getConnection();
                ps = conn.prepareStatement("select * from account where name=?");
                ps.setString(1, userName);
                rs = ps.executeQuery();
                if (rs.next()) {
                    Object principal = userName;
                    Object credentials = rs.getString(3);
                    String realmName = this.getName();
                    // 设置盐值
                    ByteSource salt = ByteSource.Util.bytes(userName);
    
                    // SimpleHash sh=new SimpleHash(algorithmName, source, salt,
                    // iterations);
                    // 加密类型 加密资源 盐值加密 加密次数
                    // 给从数据库中拿到的密码做MD5的加密
                    SimpleHash sh = new SimpleHash("SHA1", credentials, salt, 1024);
                    // info = new SimpleAuthenticationInfo(principal, credentials,
                    // realmName);
                    // info = new SimpleAuthenticationInfo(principal, sh,
                    // realmName);
                    // 通过关于盐值的构造器,将前端传入的密码在加密时再加入盐值
                    info = new SimpleAuthenticationInfo(principal, sh, salt,
                            realmName);
                } else {
                    throw new AuthenticationException();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally{
                 JdbcUtils.closeResultSet(rs);
                 JdbcUtils.closeConnection(conn);
            }
            return info;
        }
    
        /**
         * 设置role验证
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(
                PrincipalCollection principals) {
            // 返回值:AuthorizationInfo:封装获取用户对应所有角色,SimpleAuthorizationInfo(Set<String>)
            // 参数列表:PrincipalCollection登录的身份,登录的用户名
            SimpleAuthorizationInfo info = null;
            Connection conn=null;
            PreparedStatement ps =null;
            ResultSet rs =null;
            try {
                /*Class.forName("com.mysql.jdbc.Driver");
                String url = "jdbc:mysql://localhost:3306/test";
                Connection conn = DriverManager.getConnection(url, "root", "");*/
                   conn = dataSource.getConnection();
                    ps = conn.prepareStatement("select * from account where name=?");
                    String userName = principals.toString();
                    ps.setString(1, userName);
                    rs = ps.executeQuery();
                if (rs.next()) {
                    Set<String> roles = new HashSet<String>();
                    roles.add(rs.getString(4));
                    info = new SimpleAuthorizationInfo(roles);
                } else {
                    throw new AuthenticationException();
                }
            }  catch (SQLException e) {
                e.printStackTrace();
            } finally{
                JdbcUtils.closeResultSet(rs);
                JdbcUtils.closeConnection(conn);
            }
            return info;
        }
    
    }
    package com.shiro.bean;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.HashSet;
    import java.util.Set;
    
    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.authc.UsernamePasswordToken;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.crypto.hash.SimpleHash;
    import org.apache.shiro.realm.jdbc.JdbcRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.util.ByteSource;
    import org.apache.shiro.util.JdbcUtils;
    
    /**
     * @author layne Action方法中执行subject.login(token)时会通过IOC容器调取Realm域进行数据和前端数据比对
     */
    
    //public class ShiroRealm extends  AuthorizingRealm {
    public class ShiroRealm extends JdbcRealm {
        /**
         * Returns all principals associated with the corresponding Subject. Each
         * principal is an identifying piece of information useful to the
         * application such as a username, or user id, a given name, etc - anything
         * useful to the application to identify the current <code>Subject</code>.
         * The returned PrincipalCollection should <em>not</em> contain any
         * credentials used to verify principals, such as passwords, private keys,
         * etc. Those should be instead returned by {@link #getCredentials()
         * getCredentials()}.
         * 
         * @return all principals associated with the corresponding Subject.
         * 
         *         doGetAuthenticationInfo,获取认证消息,如果数据库没有数据,返回null.
         *         AuthenticationInfo可以使用 SimpleAuthenticationInfo实现类,封装给正确用户名和密码
         *         token参数:需要验证的token
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(
                AuthenticationToken token) throws AuthenticationException {
            /**
             * 1.将token转换为UsernamePasswordToken 2.获取用户名 3.查询数据库,进行验证 4.结果返回
             * 5.验证不通过,抛出异常
             */
            // 1.将token转换为UsernamePasswordToken
            UsernamePasswordToken upToken = (UsernamePasswordToken) token;
            // 2.获取用户名
            String userName = upToken.getUsername();
            // 获取用户名后。通过查询用户名查询数据库是否有值,有值则进行密码验证。
            SimpleAuthenticationInfo info = null;
            // 3。查询数据库
            // 使用JDBC链接数据库进行查询
            
            Connection conn =null;
            ResultSet rs  =null;
            try {
                /*Class.forName("com.mysql.jdbc.Driver");
                String url = "jdbc:mysql://localhost:3306/test";
                Connection conn = DriverManager.getConnection(url, "root", "");*/
                conn = dataSource.getConnection();
                PreparedStatement ps = conn.prepareStatement("select * from account where name=?");
                ps.setString(1, userName);
                rs = ps.executeQuery();
                if (rs.next()) {
                    Object principal = userName;
                    Object credentials = rs.getString(3);
                    String realmName = this.getName();
                    // 设置盐值
                    ByteSource salt = ByteSource.Util.bytes(userName);
                    // SimpleHash sh=new SimpleHash(algorithmName, source, salt,
                    // iterations);
                    // 加密类型 加密资源 盐值加密 加密次数
                    // 给从数据库中拿到的密码做MD5的加密
                    SimpleHash sh = new SimpleHash("MD5", credentials, salt, 1024);
                    // info = new SimpleAuthenticationInfo(principal, credentials,
                    // realmName);
                    // info = new SimpleAuthenticationInfo(principal, sh,
                    // realmName);
                    // 通过关于盐值的构造器,将前端传入的密码在加密时再加入盐值
                    info = new SimpleAuthenticationInfo(principal, sh, salt,
                            realmName);
                } else {
                    throw new AuthenticationException();
                }
            }catch (SQLException e) {
                e.printStackTrace();
            }finally{
                JdbcUtils.closeResultSet(rs);
                JdbcUtils.closeConnection(conn);
            }
            return info;
        }
        /**
         * 设置role验证
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(
                PrincipalCollection principals) {
            // 返回值:AuthorizationInfo:封装获取用户对应所有角色,SimpleAuthorizationInfo(Set<String>)
            // 参数列表:PrincipalCollection登录的身份,登录的用户名
            SimpleAuthorizationInfo info = null;
            
            Connection conn =null;
            ResultSet rs  =null;
            try {
                /*Class.forName("com.mysql.jdbc.Driver");
                String url = "jdbc:mysql://localhost:3306/test";
                Connection conn = DriverManager.getConnection(url, "root", "");*/
                conn = dataSource.getConnection();
                PreparedStatement ps = conn.prepareStatement("select * from account where name=?");
                String userName = principals.toString();
                ps.setString(1, userName);
                rs = ps.executeQuery();
                if (rs.next()) {
                    Set<String> roles = new HashSet<String>();
                    roles.add(rs.getString(4));
                    info = new SimpleAuthorizationInfo(roles);
                } else {
                    throw new AuthenticationException();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }finally{
                JdbcUtils.closeResultSet(rs);
                JdbcUtils.closeConnection(conn);
            }
            return info;
        }
    }
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans.xsd">
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
           <property name="driverClass" value="${driverClass}"></property>
           <property name="jdbcUrl" value="${url}"></property>
           <property name="user" value="${user}"></property>
           <property name="password"  value="${password}"></property>
        </bean> 
        
        <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
          <property name="location"  value="classpath:hibernate.properties" />
        </bean>
        
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="cacheManager" ref="cacheManager"/>
            <property name="authorizer" ref="authorizer"></property>
            <property name="authenticator" ref="authentictor"></property>
        </bean> 
        <bean id="authorizer" class="org.apache.shiro.authz.ModularRealmAuthorizer">
           <property name="realms">
              <list>
                  <ref bean="jdbcRealm"/>
                  <ref bean="defaultRealm"/>
              </list>
           </property>
        </bean>
        
        <bean id="authentictor"  class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
          <property name="realms">
              <list>
                  <ref bean="jdbcRealm"/>
                  <ref bean="defaultRealm"/>
              </list>
           </property>
        </bean>
         <!-- <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="cacheManager" ref="cacheManager"/>
            <property name="auticationtor" ref="auticationtor"></property>
         </bean>
         <bean name="auticationtor" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
            <property name="realms">
               <list>
                    <ref bean=""/>
                    <ref bean=""/>
               </list>
            </property>
            <property name="authenticationStrategy" ref="allSuccessfulStrategy"/>
         </bean>
         <bean id="allSuccessfulStrategy" class="org.apache.shiro.authc.pam.AllSuccessfulStrategy"/> -->
        
        <bean id="jdbcRealm" class="com.shiro.bean.ShiroRealm">
            <property name="dataSource" ref="dataSource"></property>
             <!-- 配置密码加密使用MD5加密 -->
             <property name="credentialsMatcher">
               <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                  <property name="hashAlgorithmName" value="MD5"></property>
                  <property name="hashIterations" value="1024"></property>
               </bean>
             </property>
            
        </bean>
        
        <bean id="defaultRealm" class="com.shiro.bean.SecondRealm">
             <property name="dataSource" ref="dataSource"></property>
             <!-- 配置密码加密使用SHA1加密 -->
             <property name="credentialsMatcher">
               <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                  <property name="hashAlgorithmName" value="SHA1"></property>
                  <property name="hashIterations" value="1024"></property>
               </bean>
             </property>
        </bean>
        <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
            <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/> 
        </bean>
       
        <!-- 必须要有这样一个实例,用来管理在Spring容器当中的Shiro常见的对象 -->
        <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
        <!-- 启用Shiro注解 -->
        <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
              depends-on="lifecycleBeanPostProcessor"/>
        <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
            <property name="securityManager" ref="securityManager"/>
        </bean>
        <!-- 网络方面 -->
        <bean id="secureRemoteInvocationExecutor" class="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor">
            <property name="securityManager" ref="securityManager"/>
        </bean>
        <!-- 
                                             配置ShiroFilter
            1.shiroFilter这个bean的id必须与web.xml文件中的filter-name保持一致
         -->
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager"/>
            <property name="loginUrl" value="/login.jsp"/>
            <property name="successUrl" value="/success.jsp"/>
            <property name="unauthorizedUrl" value="/adb.jsp"/>
            <!-- shiro过滤器具体配置 -->
            <property name="filterChainDefinitions">
                <value>
                    /login.jsp = anon
                    /login = anon
                    /logout =logout
                    /admin.jsp=roles[admin]
                    /user.jsp=roles[user]
                    /** = authc
                </value>
            </property>
        </bean>
    </beans>
    driverClass=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/test
    user=root
    password=
    <?xml version="1.0" encoding="UTF-8"?>
    <beans  xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:mvc="http://www.springframework.org/schema/mvc" 
            xmlns:context="http://www.springframework.org/schema/context" 
            xsi:schemaLocation="
                http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/mvc 
                http://www.springframework.org/schema/mvc/spring-mvc.xsd
                http://www.springframework.org/schema/context 
                http://www.springframework.org/schema/context/spring-context.xsd"> 
                <!-- 视图资源管理器 -->
                <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                   <property name="prefix" value="/"></property>
                   <property name="suffix" value=".jsp"></property>
                </bean>
                
                
                <context:component-scan base-package="*"></context:component-scan>
                <mvc:annotation-driven></mvc:annotation-driven>
                <mvc:default-servlet-handler/>
    </beans>
  • 相关阅读:
    HTML5新特性,新的 Input 类型
    HTML5新特性,拖放(Drag 和 Drop)
    剑指 Offer 32
    剑指 Offer 28. 对称的二叉树
    993. 二叉树的堂兄弟节点
    897. 递增顺序查找树
    872. 叶子相似的树
    637. 二叉树的层平均值
    617. 合并二叉树
    559. N叉树的最大深度
  • 原文地址:https://www.cnblogs.com/flytogalaxy/p/7718215.html
Copyright © 2011-2022 走看看