spring 集成 shiro安全框架

基于xml 配置文件集成

 

1. web.xml 文件

<!-- 配置Shiro安全过滤器 -->
<filter>
    <filter-name>shiroFilter</filter-name>
    <!-- 此类由spring-web 提供 -->
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
        <!-- 这个参数名在DelegatingFilterProxy中定义 -->
        <param-name>targetBeanName</param-name>
        <!-- 这个值在spring-shiro.xml配置文件中定义 -->
        <param-value>shiroFilterFactory</param-value>
    </init-param>
</filter>

<filter-mapping>
  <filter-name>shiroFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

 

shiro 的配置文件

spring-shiro.xml

       <!-- 配置SecurityManager对象,(Shiro框架核心,负责调用相关组件,实现
       用户身份认证,缓存,会话管理等功能 -->
       <bean id="securityManager"
                   class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
                   <property name="Realm" ref="shiroUserRealm"></property>
       </bean>
       <!-- 配置ShiroFilterFactoryBean对象
       (Shiro中会通过很多过滤器对WEB请求做预处理 ,这些过滤器的创建
       底层设计了一个工厂类-->
       <bean id="shiroFilterFactory" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
               <!-- 注入securityManager对象 -->
               <property name="SecurityManager" ref="securityManager"></property>
               <!-- 配置登录页面 -->
               <property name="LoginUrl" value="/doLoginUI.do"></property>
               <!-- 过滤给则(哪些资源允许匿名访问,哪些资源需要授权访问)
                       anon:允许匿名访问    authc需要授权访问 -->
               <property name="FilterChainDefinitionMap">
                   <map>
                       <entry key="/bower_components/**" value="anon"></entry>
                       <entry key="/build/**" value="anon"></entry>
                       <entry key="/dist/**" value="anon"></entry>
                       <entry key="/plugins/**" value="anon"></entry>
                       <entry key="/doLogin.do" value="anon"></entry>
              <entry key="/doLogout.do" value="logout"></entry>  //登出操作 <entry key="/**" value="authc"></entry><!-- 必须认证 --> </map> </property> </bean>

 

Realm:

package com.demo.realm;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
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 org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.demo.entity.SysUser;
import com.demo.mapper.SysUserDao;


/**
 * 借助此对象访问用户身份信息,权限信息并对
 * 其进行封装,返回给调用者.
 * 思考?
 * 1)此对象由谁来调用?(认证管理器,授权管理器)
 * @author adminitartor
 */
@Service
public class ShiroUserRealm extends AuthorizingRealm {

    @Autowired
    private SysUserDao sysUserDao;
    
    //ConcurrentHashMap()在jdk1.5之后推出,在1.8和1.8之后
    //添加了红黑树
    private Map<String, SimpleAuthorizationInfo> authMap=
            new ConcurrentHashMap<String, SimpleAuthorizationInfo>();
    
    /***
     * 完成授权信息的获取以及封装.
     * 此方法何时调用?(执行授权检测时调用)
     * 
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        System.out.println("realm.doGetAuthorizationInfo");
        //1.获取登陆用户身份信息,(基于登录认证时传递的主身份)
        String username=
        (String)principals.getPrimaryPrincipal();
        //查询缓存中是否有这个
        if(authMap.containsKey(username))
            return authMap.get(username);
        //2.查找用户的权限信息
        List<String> list=//sys:user:update,sys:user:view,....,
        sysUserDao.findUserPermissions(username);
        System.out.println("list="+list);
        //去重去空
        Set<String> permissions=new HashSet<String>();
        for(String permission:list){
            if(!StringUtils.isEmpty(permission)){
                permissions.add(permission);
            }
        }
        System.out.println("====查询认证信息");
        //3.对权限信息进行封装
        SimpleAuthorizationInfo info=
        new SimpleAuthorizationInfo();
        info.setStringPermissions(permissions);
        authMap.put(username, info);
        return info;
    }
    /**
     * 完成认证信息的获取以及封装
     * 此方法何时调用?(执行登陆认证时调用)
     * @param  
     * 用于接收用户身份以及凭证信息的对象(用户输入的)
     * 
     * @return AuthenticationInfo  
     * 封装了认证信息的对象(从数据库查询到的)
     * 
     * client-->controller-->service-->realm
     */
    @Override
    protected AuthenticationInfo 
    doGetAuthenticationInfo(
            AuthenticationToken token) 
                    throws AuthenticationException {
        System.out.println("进行身份认证");
        //1.获取用户身份信息
        UsernamePasswordToken uToken=
        (UsernamePasswordToken)token;
        String username=uToken.getUsername();
        //String username=token.getPrintcipal();
        //2.基于用户身份查询数据库信息
        SysUser sysUser=
        sysUserDao.findUserByUserName(username);
        if(sysUser==null)
            throw new UnknownAccountException("密码或账号错误");
        if(sysUser.getValid()==0){
            throw new LockedAccountException("用户被锁定");
        }
        //3.对查询结果进行封装.
        //3.1获取用户salt值,并将其转换为一个字节源对象
        ByteSource byteSource=
        ByteSource.Util.bytes(sysUser.getSalt());
        //3.2对用户信息进行封装返回.
        AuthenticationInfo info=
        new SimpleAuthenticationInfo(
            sysUser.getUsername(), //主身份
            sysUser.getPassword(), //已加密的密码
            byteSource,//salt对应的字节源对象
            getName());//realm 的名字
        return info;
    }
    
    
    /**
     * 设置凭证(密码)匹配器
     */
    @Override
    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
        HashedCredentialsMatcher hMatcher = new HashedCredentialsMatcher();
        //设置加密算法
        hMatcher.setHashAlgorithmName("MD5");
        //设置加密次数
        //hMatcher.setHashIterations(5);
        
        super.setCredentialsMatcher(hMatcher);
    }

}

 

 

认证流程图:

 

 认证和记住我:

subject.isAuthenticated()  表示用户进行了身份验证登录的,即使有Subject.login 进行了登录

subject.isRemembered()  表示用户是通过 记住我 登录的,此时可能不是真正的你(如果你的朋友使用了你的电脑,或者你的Cookie被窃取)在访问的

两者二选一。即subject.isAuthenticate()==true,则subject.isRemembered()==false,反之一样。

 

 

  流程解析:

    当客户端访问服务器时,DelegatingFilterProxy 对象会拦截所有的请求路径,并把它交给ShiroFilterFactoryBean对象处理,ShiroFilterFactoryBean对象中注入了SecurityMananger对象,负责调用相关组件,实现用户身份认证,缓存,会话管理等功能。

    ShiroFilterFactoryBean对象中还配置了FilterChainDefinitionMap这个参数,这个参数其实也相当于一个过滤器,他定义了哪些资源外部可以直接进行访问,哪些资源需要认证之后才能访问。ShiroFilterFactoryBean对象还对LoginUrl这个参数进行了设置,这个参数主要意义为:FilterChainDefinitionMap拦截的请求,直接重定向到LoginUrl这个参数配置的路径进行访问。

 

posted @ 2019-09-07 20:56  我爱si搬砖  阅读(245)  评论(0编辑  收藏  举报