因为web项目的核心组件(Service,dao)都在spring工厂中管理,利用IOC和AOP,组建了关系松散,稳健的系统。
shiro的诸多组件也需要由spring统一管理,进而可以更好的和其他组件协作,因为shiro中大多数组件都是pojo类,更方便管理我们可以很方便地把它们从shiro.ini中迁到Spring工厂中。
pom文件
<!-- 其他依赖和web集成中 一致 ,此处省略-->
<!-- 新增一个依赖 用于在工厂中生产 ShiroFilter-->
<!-- 会传递导入shiro-core 和 shiro-web -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
applicationContext_shiro.xml配置文件
将shiro的三大核心组件SecurityMnager,Subject,Realm,放到配置文件,这里我们可以将shiro单独放到一个配置文件中,在Spring的配置文件中导入该配置文件即可。
<!-- shiro配置 -->
<!--注入自定义realm组件-->
<bean id="myRealm" class="com.lsw.realm.MyRealm">
<property name="userService" ref="userServiceImpl"/>
<property name="roleService" ref="roleServiceImpl"/>
<property name="permissionService" ref="permissionServiceImpl"/>
<!--配置密码对比器 登陆时realm会根据盐迭代次数以及加密算法 来得出用户信息来对比数据库中的用户信息 进行身份验证-->
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!--声明迭代次数-->
<property name="hashIterations" value="10000"/>
<!--声明加密算法-->
<property name="hashAlgorithmName" value="SHA-256"/>
<!--声true=hex格式 false=base64格式明-->
<property name="storedCredentialsHexEncoded" value="false"/>
</bean>
</property>
</bean>
<!--注入安全管理器securityManager-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!--将realm注入-->
<property name="realm" ref="myRealm"/>
<!--将rememberMeManager注入-->
<property name="rememberMeManager" ref="rememberMeManager"/>
<!--注入session管理器-->
<property name="sessionManager" ref="sessionManager"/>
</bean>
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!--注入核心组件-->
<property name="securityManager" ref="securityManager"/>
<!--声明未登录 没权限的-->
<property name="loginUrl" value="/user/login"/>
<property name="unauthorizedUrl" value="/user/error"/>
<!--过滤器链 这里后面可以用注解代替 -->
<property name="filterChainDefinitions">
<value>
/user/login = anon
/user/login = anon
/user/all = authc,roles["admin"]
/user/update = authc,roles["manager","seller"]
/user/delete = authc, perms["user:update","user:delete"]
/user/logout = logout
</value>
</property>
</bean>
<!--自定义记住我-->
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<!-- cookie的生命周期,单位:秒 7天-->
<property name="maxAge" value="2592000"/>
<property name="name" value="rememberMe"/>
<!-- cookie只在http请求中可用,那么通过js脚本将无法读取到cookie信息,有效防止cookie被窃取 -->
<property name="httpOnly" value="true"/>
</bean>
<!--记住我管理器-->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<property name="cookie" ref="rememberMeCookie"/>
</bean>
<!-- 增加session管理相关配置 -->
<!-- 会话Cookie模板 默认可省-->
<bean id="simpleCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<property name="name" value="JSESSIONID04"/>
<!-- cookie过期时间,-1:存活一个会话 ,单位:秒 ,默认为-1-->
<property name="maxAge" value="-1"/>
<property name="httpOnly" value="true"/>
</bean>
<!--session管理器-->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!-- 默认值和配置中给出的一致,所bean:sessionIdCookie 可以省略 -->
<property name="sessionIdCookie" ref="simpleCookie"/>
<!-- session全局超时时间, 单位:毫秒 ,30分钟 默认值为1800000 默认设置为10s-->
<property name="globalSessionTimeout" value="10000"/>
<!--注入session监听器-->
<property name="sessionListeners">
<list>
<bean class="com.lsw.session.MySessionListener"/>
</list>
</property>
<!--session检测 可以省略不写 有默认配置-->
<!--session默认开启 但是默认时间比较长 30分钟 我们可以更改时间 来观察-->
<property name="sessionIdUrlRewritingEnabled" value="true"/>
<!-- 更改 检测间隔时间 15s-->
<property name="sessionValidationInterval" value="15000"/>
</bean>
web.xml
<!-- 会从spring工厂中获取和它同名的bean,(id="shiroFilter")
接到请求后调用bean的doFilter方法,进行访问控制。
因为这里本来是ShiroFilter的 我们将它放在了工厂内部 所有在web中需要定义这样一个来代替shiroFilter来拦截所有请求 然后找到工厂中预期filterName对应的ShiroFilter进行操作过滤
-->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- EnvironmentLoaderListener不再需要,因为shiro环境已由spring初始化
springMVC,spring配置不变 -->
另外大家发现了我们在这里也直接整合了Mybatis。因为之前我们放在shiro.ini中的用户名,权限和角色信息都没有了 ,这里我们自定义了pojo类 将权限角色信息存入数据库中,在需要安全数据时候 在自定义的Realm中注入service并调用dao来进行数据库查询即可 贴一下大概结构图 和realm的代码。
大概结构:(将角色权限分别定义pojo,并将数据存在数据库,由realm中调用service,dao来查询)
自定义realm
@Setter
public class MyRealm extends AuthorizingRealm {
private UserService userService;//注入service 调用其中dao查询方法即可
private PermissionService permissionService;
private RoleService roleService;
@Override
//用户做授权和权限认定
/**
* 当subject.login()时,shiro会调用Realm的此方法做用户信息的查询,然后做校验
* 职责:通过用户传递来的用户名查询用户表,获得用户信息
* 返回值:将查到的用户信息(用户名+密码)封装在AuthenticationInfo对象中返回
* 异常:如果没有查到用户可抛出用户不存在异常;如果用户被锁定可抛出用户被锁异常;或其它自定义异常.
* @param token
* @return
* @throws AuthenticationException
*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取shiro中的用户名
String username = (String) principalCollection.getPrimaryPrincipal();
//根据用户姓名去表中查询用户角色和权限信息
//根据用户名查询角色信息
// RoleService roleService = ContextLoader.getCurrentWebApplicationContext().getBean("roleServiceImpl", RoleService.class);
Set<String> roles = roleService.queryAllRolenameByUsername(username);
//根据用户名查权限信息
// PermissionService permissionService =ContextLoader.getCurrentWebApplicationContext().getBean("permissionServiceImpl", PermissionService.class);
Set<String> permissions = permissionService.queryAllPermissionByUsername(username);
//将用户权限和角色信息 封装到对象中
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(roles);
simpleAuthorizationInfo.setStringPermissions(permissions);
return simpleAuthorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String username = (String) authenticationToken.getPrincipal();
//根据用户名来查询用户身份信息
// UserService userService = (UserService)ContextLoader.getCurrentWebApplicationContext().getBean("userServiceImpl");
//System.out.println("================"+userService);
User user = userService.queryUserByUsername(username);
if(user==null){
return null; //返回空后续会返回一个用户名不存在异常 由一场解析器处理
}
return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(), ByteSource.Util.bytes(user.getSalt()),getName());
}
}
至此 ,Spring集成shiro基本就完成了 后面想起来什么在做总结和大家分享 希望对大家有所帮助。