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.常用注解
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安全框架的使用
-
dotnet 使用 Obsolete 特性标记成员过时保持库和框架的兼容性
-
python 接口自动化测试框架-unittest框架的基本使用
-
Python之unittest框架的介绍及使用
-
Unittest框架的使用方法
-
python unittest框架的使用&解析
-
python unittest 极简自动化测试框架:二、 BeautifulReport的使用简解,生成漂亮的报告
-
使用Jquery+EasyUI框架开发项目+下载+帮助--EasyUI的简介 博客分类: 【EasyUI】 框架jqueryasp.netjavascript
-
使用多线程往同一个文件写入数据的线程安全的例子(java实现)
-
多线程使用同一个数据源的安全问题解决 三种方法: