欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Shiro安全框架的使用

程序员文章站 2024-03-22 23:04:58
...

Shiro执行流程 :
spring配置文件==>Subject==>安全管理器SecurityManager==>Realm
Shiro拦截方式 :
1.URL拦截(常用)
2.注解方式拦截(常用)
3.标签拦截
4.编码判断拦截

1.在maven中添加坐标

<!-- 权限控制 框架 -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-all</artifactId>
    <version>${shiro.version}</version>
</dependency>

2.在web.xml中配置Shiro过滤器

注意 : 如果使用struts,需要配置在struts过滤器前面

<!-- 配置shiro拦截器 -->
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

4.在spring配置文件中配置

anon 未认证可以访问
authc 认证后可以访问
perms 需要特定权限才能访问
roles 需要特定角色才能访问
user 需要特定用户才能访问
port 需要特定端口才能
注意:需要将spring的事务改成cglib代理,否则权限注解不起作用

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:task="http://www.springframework.org/schema/task"
    xmlns:jaxrs="http://cxf.apache.org/jaxrs"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/data/jpa 
        http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
        http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd ">

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- shiro 的核心安全接口 -->
        <property name="securityManager" ref="securityManager" />
        <!-- 要求登录时的链接 -->
        <property name="loginUrl" value="/login.html" />
        <!-- 登陆成功后要跳转的连接 -->
        <property name="successUrl" value="/index.html" />
        <!-- 未授权时要跳转的连接 -->
        <property name="unauthorizedUrl" value="/unauthorized.html" />
        <!-- shiro 连接约束配置 -->
        <property name="filterChainDefinitions">
            <value>
                /login.html* = anon
                /userAction_login.action* = anon
                /css/** = anon
                /js/** = anon
                /images/** = anon
                /attached/** = anon
                /upload/** = anon
                /services/* = anon
                /edit/** = anon
                /validatecode.jsp = anon
                /pages/base/courier.html* = perms[courier:list]
                /pages/base/area.html* = roles[base]
                /** = authc
            </value>
        </property>
    </bean>
    <!-- 配置 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="bosRealm" />
    </bean>
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
    <!-- 开启Shiro注解 -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" 
        depends-on="lifecycleBeanPostProcessor" >
        <!-- 必须使用cglib代理 -->
        <property name="proxyTargetClass" value="true"></property>  
    </bean>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager" />
    </bean>

</beans>

5.代码演示(登陆)

action :
@Action(value = "userAction_login")
    public String login() throws Exception {

        Subject subject = SecurityUtils.getSubject();
        AuthenticationToken token = new UsernamePasswordToken(entity.getUsername(), entity.getPassword());

        try {
            subject.login(token);
            java2Json(BosResult.ok(), new String[] {});
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            java2Json(BosResult.build(400, "账号不存在~"), new String[] {});
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            java2Json(BosResult.build(400, "密码错误~"), new String[] {});
        }
        return NONE;
    }
realm : 需要注入给SecurityManager

授权 : 在applicationContext.xml中配置的权限和角色定的路径拦截

import java.util.List;

import org.apache.shiro.SecurityUtils;
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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.itcast.bos.domain.system.Permission;
import cn.itcast.bos.domain.system.Role;
import cn.itcast.bos.domain.system.User;
import cn.itcast.bos.service.delivery.PermissionService;
import cn.itcast.bos.service.delivery.RoleService;
import cn.itcast.bos.service.delivery.UserService;

/**
 * 安全管理 Realm
 * 
 * @author Administrator
 *
 */
@Service
public class BosRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private PermissionService permissionService;

    @Override
    // 授权方法
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
        System.out.println("Shiro 授权执行...");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 获取用户信息
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        // 根据用户id查询对应角色
        List<Role> roles = roleService.findRolesByUser(user);
        for (Role role : roles) {
            info.addRole(role.getKeyword());
        }
        // 根据用户id查询对应权限
        List<Permission> permissions = permissionService.findPermissionByUser(user);
        for (Permission permission : permissions) {
            info.addStringPermission(permission.getKeyword());
        }
        return info;
    }

    @Override
    // 认证方法
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authToken) throws AuthenticationException {
        System.out.println("Shiro 认证执行...");
        // 获取页面传来的username和password
        UsernamePasswordToken token = (UsernamePasswordToken) authToken;
        // 调用业务层查询执行查询
        User user = userService.findByUsername(token.getUsername());
        if (user == null) {
            return null;
        }
        return new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
    }
}
结果:密码和用户名错误会抛出异常 ,需要对异常进行处理
    用户名不存在:
        UnknownAccountException
    密码错误:
        IncorrectCredentialsException

6.权限注解的使用(细颗粒度权限控制)

1.在spring配置文件中**注解权限

spring的事务必须是cglib代理
proxy-target-class=”true”

    <!-- 开启Shiro注解 -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" 
        depends-on="lifecycleBeanPostProcessor" >
        <!-- 必须使用cglib代理 -->
        <property name="proxyTargetClass" value="true"></property>  
    </bean>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager" />
    </bean>
2.在方法上注解
例如:
 @Override
    @RequiresPermissions("courier_add")
    public void saveCourier(Courier entity) {
        entity.setDeltag('0');// 0为正常, 1为标记作废
        courierRepository.save(entity);
    }
使用方法注解进行权限控制, 当权限不足时,代理对象抛出一个异常,需要对异常捕捉
org.apache.shiro.authz.UnauthorizedException: Subject does not
have permission [courier_add]
3.常用注解

Shiro安全框架的使用

7. 给权限添加缓存(EhCache)

问题: 为什么使用 ehcache 而不使用 redis 缓存
1、Shiro 默认对 ehcache 的支持
2、在后台管理系统中 ehcache 使用非常普遍

1.引入ehCache的maven坐标
<!-- 引入ehCache依赖 -->
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache-core</artifactId>
    <version>2.6.11</version>
</dependency>
2.复制ehcache jar包下的ehcache.xml文件
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">

    <diskStore path="java.io.tmpdir"/>

    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxElementsOnDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </defaultCache>

    <cache name="promissionCache"
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxElementsOnDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </cache>
</ehcache>
3. 在spring配置文件中配置
    <!-- 配置ehCache -->
    <bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
        <!-- 指定ehcache.xml文件的位置-->
        <property name="configLocation" value="classpath:ehcache.xml"/>
    </bean>

    <!-- 配置shiro封装ehCache -->
    <bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManager" ref="ehCacheManager"/>
    </bean>

    <bean id="bosRealm" class="cn.itcast.bos.realm.BosRealm">
        <!--注入缓存区自定义的名称-->
        <property name="authorizationCacheName" value="promissionCache"/>
    </bean>

注:最后将shiroCacheManager注入给SecurityManager
特别注意:被缓存的对象要实现序列化接口,否则会报xx类为实现序列化接口异常
运行即可

相关标签: 权限框架 shiro