shiro是Apache 推出的一个权限管理框架。
它主要有三个核心组件:
Subject :当前操作用户(人、第三方进程等)
SecurityManager :管理内部组件、提供各种安全管理服务
Realms :shiro和系统安全数据之间的“桥梁”、“连接者”,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
shiro整合spring
配置:
1.依赖
2.Web.xml
3.applicationContext.xml
配置如下图:
spring整合shiro实例:
1.application.xml(spring)文件的配置
<?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"
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">
<!-- 配置Shiro核心Filter -->
<bean id="shiroFilter"
class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 安全管理器 -->
<property name="securityManager" ref="securityManager" />
<!-- 未认证,跳转到哪个页面 -->
<property name="loginUrl" value="/login.html" />
<!-- 登录页面页面 -->
<property name="successUrl" value="/index.html" />
<!-- 认证后,没有权限跳转页面 -->
<property name="unauthorizedUrl" value="/unauthorized.html" />
<!-- shiro URL控制过滤器规则
anon 未认证可以访问,直接放行
authc 认证后可以访问
perms 需要特定权限才能访问
roles 需要特定角色才能访问
user 需要特定用户才能访问
port 需要特定端口才能访问
reset 根据指定 HTTP 请求访问才能访问 -->
<property name="filterChainDefinitions">
<value>
/login.html* = anon
/user_login.action* = anon
/validatecode.jsp* = anon
/css/** = anon
/js/** = anon
/images/** = anon
/services/** = anon
<!-- securityManager查询数据库后根据结果做出操作 -->
<!-- 特定的权限才能操作 -->
/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">
<!-- 注入自定义的realm -->
<property name="realm" ref="bosRealm" />
<!-- <property name="cacheManager" ref="shiroCacheManager" /> -->
</bean>
<!-- 配置Realm:范围、领域 -->
<!-- <bean id="bosRealm" class="cn.boom.bos.realm.BosRealm">
缓存区的名字 就是 ehcache.xml 自定义 cache的name
<property name="authorizationCacheName" value="bos" />
</bean> -->
<bean id="lifecycleBeanPostProcessor"
class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean>
<!-- 开启shiro注解模式 -->
<bean
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor" >
<!-- 设置为使用cglib方式的动态代理 -->
<property name="proxyTargetClass" value="true" />
</bean>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
</beans>
自定义的Realm:
package cn.boom.bos.realm;
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.boom.bos.domain.system.Permission;
import cn.boom.bos.domain.system.Role;
import cn.boom.bos.domain.system.User;
import cn.boom.bos.service.system.PermissionService;
import cn.boom.bos.service.system.RoleService;
import cn.boom.bos.service.system.UserService;
/**
* 自定义的realm,继承Realm接口,实际开发中只需要继承AuthorizingRealm
* @author peng 2018年3月26日
*
*/
//在配置文件中配置了
@Service("bosRealm")
public class BosRealm extends AuthorizingRealm{
@Autowired
private UserService userService;
@Autowired
private RoleService roleService;
@Autowired
private PermissionService permissionService;
/*
* 授权
* @see org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
System.out.println("测试:shiro的授权管理");
//注意应为org.apache.shiro.authz.SimpleAuthorizationInfo;
//simpleAuthorizationInfo : 简单的授权信息
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
/*根据当前登陆的用户获得其角色和权限*/
Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();
//调用业务层查询其角色
List<Role> roles = roleService.findByUser(user);
for (Role role : roles) {
String keyword = role.getKeyword();
simpleAuthorizationInfo.addRole(keyword);
}
//调用业务层,查询权限
List<Permission> permissions = permissionService.findByUser(user);
for (Permission permission : permissions) {
String keyword = permission.getKeyword();
simpleAuthorizationInfo.addStringPermission(keyword);
}
return simpleAuthorizationInfo;
}
/*
* 认证
* @see org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)
* 返回的类型为 new SimpleAuthenticationInfo(principal, credentials, realmName)
* 参数一: 期望登录后,保存在Subject中信息
* 参数二: 如果返回为null 说明用户不存在,报用户名
* 参数三 :realm名称
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
System.out.println("测试:shiro的认证管理");
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
User user
= userService.findByUsername(usernamePasswordToken.getUsername());
System.out.println("测试 传过来的密码为:"+usernamePasswordToken.getPassword());
if (user == null) {
return null;
} else {
// 当返回用户密码时,securityManager安全管理器,自动比较返回密码和用户输入密码是否一致
// 如果密码一致 登录成功, 如果密码不一致 报密码错误异常
System.out.println("测试 返回的密码为"+user.getPassword());
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
}
}
}
action示例:
package cn.boom.bos.web.action.system;
/**
*
* @author peng 2018年3月26日
*
*/
@Controller
@Scope("prototype")
@Namespace("/")
@ParentPackage("json-default")
public class UserAction extends BaseAction<User>{
/*
* 用户登录,基于权限控制
*/
@Action(value="user_login",results={
@Result(name="login",type="redirect",location="login.html"),
@Result(name="success",type="redirect",location="index.html")
})
public String login(){
//基于shiro实现权限控制
Subject subject = SecurityUtils.getSubject();
//用户的用户名及密码信息
AuthenticationToken token =
new UsernamePasswordToken(model.getUsername(), model.getPassword());
try {
//登录
subject.login(token); //执行Realm中的认证方法
System.out.println("测试:登录成功");
return SUCCESS;
} catch (AuthenticationException e) {
System.err.println("登录过程发生错误");
e.printStackTrace();
}
return "login";
}
/*
* 用户注销
*/
@Action(value="user_logout",results={
@Result(name="success",type="redirect",location="login.html")
})
public String logout(){
//查询到当前的用户 , 并自动操作session完成注销
Subject subject = SecurityUtils.getSubject();
subject.logout();
return SUCCESS;
}
}