SSM整合shiro权限框架

一、SSM整合shiro框架

1.步骤

1.添加shiro框架需要的jar包,包括shiro-core、shiro-web、shiro-spring的关系依赖

        <!-- shiro jar包依赖 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro.version}</version>
        </dependency>

2.在web.xml文件中配置shiro的过滤器

    <!-- 配置shiro框架的过滤器 -->
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
​
        <!-- 设置true由servlet容器控制filter的生命周期 -->
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
        <!-- 设置spring容器filter的bean id,如果不设置则找与filter-name一致的bean -->
        <init-param>
            <param-name>targetBeanName</param-name>
            <param-value>shiroFilter</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!-- 添加字符集过滤器 -->
    <filter>
        <filter-name>encoding</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>encoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

3.添加applicationContext.shiro.xml文件,添加在web.xml中filter对应的spring容器对应的bean

4.静态资源处理

    <!-- web.xml中shiro的filter对应的bean -->
    <!-- Shiro 的Web过滤器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <!-- loginUrl认证提交地址,如果没有认证将会请求此地址进行认证,请求此地址将由formAuthenticationFilter进行表单认证 -->
        <property name="loginUrl" value="/login.do" />
        <!-- 认证成功统一跳转到first.action,建议不配置,shiro认证成功自动到上一个请求路径 -->
        <property name="successUrl" value="/index.do" />
        <!-- 通过unauthorizedUrl指定没有权限操作时跳转页面 -->
        <property name="unauthorizedUrl" value="/nofunc.jsp" />
​
        <!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 -->
        <property name="filterChainDefinitions">
            <value>
                <!-- 对静态资源设置匿名访问 -->
                /static/* = anon
                /login.do = anon
                /toLogin.do=anon
                <!-- 过滤器对资源进行验证 -->
                /index.do = authc
                <!-- 请求 logout地址,shiro去清除session -->
                /logout.do = logout
                <!-- 具有指定的权限才能访问 -->
                /userManager.do = perms[user:manager]
                /roleManager.do = perms[role:manager]
                /toUserRole.do = perms[user:pression]
                <!-- /* = authc 所有url都必须认证通过才可以访问 -->
                /* = authc
            </value>
        </property>
    </bean>
    <!-- securityManager安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="authenRealm" />
    </bean>
    <!-- realm -->
    <bean id="authenRealm" class="com.demo.realm.AuthenRealms">
        <!-- 将凭证匹配器设置到realm中,realm按照凭证匹配器的要求进行散列 -->
        <property name="credentialsMatcher" ref="credentialsMatcher" />
    </bean>
    <!-- 凭证匹配器 -->
    <bean id="credentialsMatcher"
        class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <property name="hashAlgorithmName" value="md5" />
        <property name="hashIterations" value="1" />
    </bean>

5.自定义AuthenRalms

public class AuthenRealms extends AuthorizingRealm {
​
    @Resource
    IUserService userService;
    @Resource
    IFunctionService functionService;
    /**
     * 授权方法
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //获取当前用户信息
        User user = (User)principals.getPrimaryPrincipal();
        List<String> perms = new ArrayList<String>();
        //List<String> roles = new ArrayList<String>();
        //根据用户信息获取所属于角色
        
        //根据角色查权限
        List<Function> functions = functionService.findByUserId(user.getUserId());
        for(Function func : functions){
            perms.add(func.getFuncCode());
        }
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //把所有的权限串列表都放到SimpleAuthorizationInfo对象中
        authorizationInfo.addStringPermissions(perms); 
        //authorizationInfo.addRoles(roles);//放置所有的角色信息
        
        return authorizationInfo;
    }
    /**
     * 认证方法
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //获取用户名名称
        String username = token.getPrincipal().toString();
        //通过用户名获取用户对象
        User user = userService.login(username, null);
        //把user对象封装的AuthenticationInfo中返回
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user,user.getPassword(),ByteSource.Util.bytes(user.getSalt()),"authenRealm");
        return authenticationInfo;
    }
​
}

6.登陆

	@RequestMapping("/login.do")
	public String login(String username,String password,HttpServletRequest request){
		//当用户名称和密码都不为空的情况下,通过用户名和密码进行数据库查询校验
		//获取当前的主体对象
		Subject subject = SecurityUtils.getSubject();
		
		//创建用户登录验证令牌
		UsernamePasswordToken token = new UsernamePasswordToken(username,password);
		try {
			subject.login(token);
			boolean flag = subject.isAuthenticated();
			if(flag){ //验证通过
				//把用户对象信息放入到session中
				User user = (User)subject.getPrincipal();
				subject.getSession().setAttribute("user",user);
				return "success";
			}else{
				return "login";
			}
		} catch (Exception e) {
			e.printStackTrace();
			return "login";
		}
	}

二、实现shiro框架的授权

1.基于xml配置文件的授权

在applicationContext-shiro中配置

<!-- 具有指定的权限才能访问 -->
/userManager.do = perms[user:manager]
/roleManager.do = perms[role:manager]
/toUserRole.do = perms[user:pression]

2.基于注解方式的授权

在springmvc配置文件中添加shiro注解的支持和spring aop代理的支持

    <!-- 开启aop,对类代理 -->
    <aop:config proxy-target-class="true"></aop:config>
    <!-- 开启shiro注解支持 -->
    <bean
    class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"></property>
    </bean>

在控制器上添加权限验证的注解

//需要具有function:manager权限,才能执行该控制器方法
@RequiresPermissions(value={"function:manager"})
    @RequestMapping("/functionManager.do")
    public String functionManager() {
        return "success";
    }

3.基于jsp页面标签的授权

jsp页面添加

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

常见标签:

标签名称 标签条件
shiro:authenticated 登陆之后
shiro:notAuthenticated 没有登陆
shiro:guest 用户在没有RemberMe时
shiro:user 用户在RemberMe时
<shiro:hasAnyRoles name="admin,user"> 在有admin和user角色时
<shiro:hasRole name="admin"> 拥有角色admin
<shiro:lacksRole name="admin"> 没有角色admin
<shiro:hasPermission name="abc"> 拥有权限资源abc
<shiro:lacksPermission name="abc"> 没有abc权限资源
shiro:principal 显示用户身份名称
<shiro:principal property="username"> 显示用户身份中的属性值
    <shiro:notAuthenticated>没有登录时显示该信息</shiro:notAuthenticated>
    <shiro:authenticated>登录后显示该信息!</shiro:authenticated>
​
    <shiro:authenticated>
        登录后显示的内容!
    </shiro:authenticated>
    
    用户名:<shiro:principal property="userName"></shiro:principal><br>
    密码:<shiro:principal property="password"></shiro:principal><br>
    email:<shiro:principal property="email"></shiro:principal>
    
    <br>
    权限判断:
    <shiro:hasPermission name="function:add">
        <a href="/addFunction.do">添加菜单</a>
    </shiro:hasPermission>
    <shiro:hasPermission name="function:update">
        <a href="/updateFunction.do">修改菜单</a>
    </shiro:hasPermission>
    <shiro:hasPermission name="function:delete">
        <a href="/deleteFunction.do">删除菜单</a>
    </shiro:hasPermission>

4.退出操作

在shiro.xml配置文件中配置退出过滤器,shiro自动完成系统的退出操作

<!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 -->
<property name="filterChainDefinitions">
    <value>
      ...
      /logout.do = logout
      ...
    </value>
</property>

在前端页面直接调用logout.do即可销毁session退出系统

<script type="text/javascript">
    function logoutSys(){
        document.location.href="logout.do";
    }
</script>
​
    <input type="button" name="btn" value="退出" onclick="logoutSys()">

三、shiro集成缓存管理

1.缓存的流程

  • shiro中提供了对认证信息和授权信息的缓存,shiro默认是关闭认证信息缓存的。对于授权信息的缓存shiro默认是开启的,因为授权信息的数据量比较大,所以我们要对授权信息进行缓存

  • shiro每次授权都会通过realm获取权限信息,为了提高访问速度需要添加缓存。第一次从realm中读取权限数据,之后不再读取

2.具体步骤

(1)导入ehcache插件的依赖

        <!-- 缓存依赖 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>${shiro.version}</version>
        </dependency>

(2)applicationContext-shiro.xml中添加配置信息

    <!-- 缓存的配置 -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml" />
    </bean>
​
    <!-- session管理器 -->
    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        <!-- 配置session的失效时长,单位是毫秒 -->
        <property name="globalSessionTimeout" value="100000"></property>
        <!-- 删除失效的session -->
        <property name="deleteInvalidSessions" value="true"></property>
    </bean>

(3)添加shiro-ehcache.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    <!--diskStore:缓存数据持久化的目录 地址  -->
    <diskStore path="E:\workspace\ehcache" />
    <defaultCache 
        maxElementsInMemory="1000" 
        maxElementsOnDisk="10000000"
        eternal="false" 
        overflowToDisk="false" 
        diskPersistent="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120" 
        diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>

3.清除缓存

  • 用户正常退出后,shiro框架会自动清除缓存信息

  • 高版本的shiro框架,用户非正常登陆也会自动清除缓存信息

  • 当用户权限修改后,用户再次登陆shiro会自动调用realm从数据库获取权限数据,如果在修改权限后向立即清除缓存可以调用realm的clearCache方法手动清除缓存

自定义realm类中定义如下方法:

    /**
     * 清除缓存
     */
    public void clearCache(){
        //获取当前主体对象
        PrincipalCollection  principal = SecurityUtils.getSubject().getPrincipals();
        super.clearCache(principal); //清除缓存
    }

修改权限数据后,调用该方法

@Service
public class UserServiceImpl implements IUserService {
    @Resource
    AuthenRealms authenRealms;
    @Resource
    IUserDao userDao;
​
    public int updateUser(User user){
        int result = userDao.updateByPrimaryKey(user);
        //调用清除缓存的方法
        authenRealms.clearCache();
        return result;
    }
}

猜你喜欢

转载自blog.csdn.net/fy_java1995/article/details/86633203