SpringMVC整合shiro(网上资料整合)

shiro基础及原理:http://kdboy.iteye.com/blog/1154644。强烈推荐非常好的文章,对shiro学习有很大帮助!

shiro例子:http://www.cnblogs.com/xql4j/archive/2013/03/30/2990920.html

跟我学shiro:http://jinnianshilongnian.iteye.com/blog/2049092

整合shiro大体步骤:

  • web.xml的配置
  • spring-shiro.xml配置
  • realm实现类
  • 认证&授权
一、web.xml
<!-- 配置Shiro过滤器,先让Shiro过滤系统接收到的请求 -->
	<!-- 这里filter-name必须对应applicationContext.xml中定义的<bean id="shiroFilter"/> -->
	<!-- 使用[/*]匹配所有请求,保证所有的可控请求都经过Shiro的过滤 -->
	<!-- 通常会将此filter-mapping放置到最前面(即其他filter-mapping前面),以保证它是过滤器链中第一个起作用的 -->
	<filter>
		<filter-name>shiroFilter</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
		<init-param>
			<!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 -->
			<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>


 
 
二、spring-shiro配置文件
2.1 applicationContext.xml 或者spring-shiro.xml的配置 (这里只保留了shiro相关的信息)
<?xml version="1.0"encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.2.xsd"
	default-lazy-init="true">
	<description>Shiro安全配置</description>   
	<!-- shiro securityManager -->    
	<!--Shiro默认会使用Servlet容器的Session, 可通过sessionMode属性来指定使用Shiro原生Session -->   
	<!--即<property name="sessionMode"value="native"/>, 详细说明见官方文档 -->    
	<!--这里主要是设置自定义的单Realm应用,若有多个Realm, 可使用'realms'属性代替 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="shiroDbRealm" />    
		<!-- <property name="cacheManager" ref="myShiroEhcacheManager" /> -->       
		<!-- <property name="sessionMode" value="native"/> <property name="sessionManager" ref="sessionManager"/> -->
	</bean>       
	<!-- 用户授权信息Cache,采用EhCache -->
	<bean id="myShiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
		<property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml" />
	</bean>     
	<!--继承自AuthorizingRealm的自定义Realm, 即指定Shiro验证用户的认证和授权 -->
	<bean id="shiroDbRealm" class="org.shiro.demo.service.realm.ShiroDbRealm"
		depends-on="baseService">
		<property name="userService" ref="userService" />
	</bean>       
	<!--Shiro主过滤器本身功能十分强大,其强大之处就在于它支持任何基于URL路径 表达式的、自定义的过滤器的执行 -->   
	<!-- Shiro Filter -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">     
	<!-- Shiro的核心安全接口,这个属性是必须的 -->
		<property name="securityManager" ref="securityManager" />    
		<!--要求登录时的链接,非必须的属性, 默认会自动寻找Web工程根目录下的"/login.jsp"页面 -->
		<property name="loginUrl" value="/" />    
		<!-- 登录成功后要跳转的连接(本例中此属性用不到, 因为登录成功后的处理逻辑在LoginController里硬编码为main.jsp了) -->
		<property name="successUrl" value="/system/main" />    
		<!-- 用户访问未对其授权的资源时,所显示的连接 -->
		<property name="unauthorizedUrl" value="/system/error" />    
		<!-- Shiro过滤链的定义 -->     
		<!-- 此处可配合这篇文章来理解各个过滤连的作用 http://blog.csdn.net/jadyer/article/details/12172839 -->        
		<!--下面value值的第一个'/'代表的路径是相对于 HttpServletRequest.getContextPath()的值来的 -->
		<!--anon:它对应的过滤器里面是空的,什么都没做, 这里.do和.jsp后面的*表示参数,比方说login.jsp?main这种 -->    
		<!-- authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器 org.apache.shiro.web.filter.authc.FormAuthenticationFilter -->
		<property name="filterChainDefinitions">
			<value> 
			/login = anon 
			/validateCode = anon 
			/** = authc       
			</value>
		</property>
	</bean>     
	<!--保证实现了Shiro内部lifecycle函数的bean执行; 起效权限注解,这个很少在web项目中用到,一般是控制url的访问,不是在controller中声明权限注解-->
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />     
	<!-- 开启Shiro的注解,实现对Controller的方法级权限检查(如 @RequiresRoles,@RequiresPermissions), 需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证 -->    
		<!--配置以下两个bean即可实现此功能 -->   
		<!-- Enable Shiro Annotations for Spring-configured beans. Only run after 
		thelifecycleBeanProcessor has run -->
	<bean
		class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
		depends-on="lifecycleBeanPostProcessor">
		<property name="proxyTargetClass" value="true" />
	</bean>
	<bean
		class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
		<property name="securityManager" ref="securityManager" />
	</bean>
</beans>

2.2 applicationContext-mvc.xml配置

         <aop:config proxy-target-class="true"></aop:config>  
	<!-- shiro注解方式必须放到mvc的文件中才会生效,不知道为什么 -->
	 <!--保证实现了Shiro内部lifecycle函数的bean执行; 起效权限注解,这个很少在web项目中用到,一般是控制url的访问,不是在controller中声明权限注解-->  
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />       
    <!-- 开启Shiro的注解,实现对Controller的方法级权限检查(如 @RequiresRoles,@RequiresPermissions), 需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证 -->      
        <!--配置以下两个bean即可实现此功能 -->     
        <!-- Enable Shiro Annotations for Spring-configured beans. Only run after   
        thelifecycleBeanProcessor has run -->  
    <bean  
        class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"  
        depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true" />
    </bean>  
    <bean  
        class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">  
        <property name="securityManager" ref="securityManager" />  
    </bean>





三、重写Realm(认证与授权)

PS:

1、认证仅需要把原程序的身份认证过程移植到此处即可,操作简单。

2、授权,shiro三种方式实现授权:编码方式、注解方式、JSP TAGLIB


<pre name="code" class="java">package com.flf.controller;


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.SimplePrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.flf.entity.User;
import com.flf.service.UserService;
import com.flf.util.Const;

@Component
public class MyRealm extends AuthorizingRealm {
	public Logger logger = LoggerFactory.getLogger(getClass());
	@Autowired
	private UserService userService;
	
	public UserService getUserService() {
		return userService;
	}
	public void setUserService(UserService userService) {
		this.userService = userService;
	}
	/** 
     * 权限认证 
     */ 
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
		
		// 因为非正常退出,即没有显式调用 SecurityUtils.getSubject().logout()
		// (可能是关闭浏览器,或超时),但此时缓存依旧存在(principals),所以会自己跑到授权方法里。
		if (!SecurityUtils.getSubject().isAuthenticated()) {
			doClearCache(principal);
			SecurityUtils.getSubject().logout();
			return null;
		}
		User user = (User) SecurityUtils.getSubject().getSession().getAttribute(Const.SESSION_USER);
		if(user != null){
			//添加角色及权限信息
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
			info.addRole("admin");
			info.addStringPermission("user:create");
			//info.addRoles(roles);
			//info.addStringPermissions(permissions)
			return info;
		}else{
			return null;
		}
	}
	/** 
     * 登录认证; 
     */ 
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		System.out.println(token.getPassword()+ "   "+token.getUsername());
		String password = token.getPassword().toString();
		// 调用业务方法
		User user = userService.getUserByNameAndPwd(token.getUsername(),new String((char[])token.getCredentials()));
		if(user!=null){
			// 要放在作用域中的东西,请在这里进行操作
			SecurityUtils.getSubject().getSession().setAttribute(Const.SESSION_USER,user);
			System.out.println(SecurityUtils.getSubject().getPrincipal());
			//info.setCredentialsSalt(ByteSource.Util.bytes(user.getUsername())) 密码加盐
			//new SimpleAuthenticationInfo(user,user.getPassword().substring(16), ByteSource.Util.bytes(salt), getName());存储user对象,授权时方便取出
			return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), ByteSource.Util.bytes("salt"), getName());//另一种加盐方式
			// Cache<Object, Object> cache =
			// shiroCacheManager.getCache(GlobalStatic.authenticationCacheName);
			// cache.put(GlobalStatic.authenticationCacheName+"-"+userName,
			// session.getId());
		}
		// 认证没有通过
		return null;
	}
	/**
     * 清空用户关联权限认证,待下次使用时重新加载。
     * 
     * @param principal
     */
    public void clearCachedAuthorizationInfo(String principal) {
        SimplePrincipalCollection principals = new SimplePrincipalCollection(
                principal, getName());
        clearCachedAuthorizationInfo(principals);
    }

}

注解方式需要springmvc也同时是controller注解或者开启aop拦截才会生效
 

2、基于注解的授权实现   |  PS:引用自:http://kdboy.iteye.com/blog/1155450

Shiro注解支持AspectJ、Spring、Google-Guice等,可根据应用进行不同的配置。 

相关的注解: 
@ RequiresAuthentication 
可以用户类/属性/方法,用于表明当前用户需是经过认证的用户。 

Java代码   收藏代码
  1. @RequiresAuthentication  
  2. public void updateAccount(Account userAccount) {  
  3.     //this method will only be invoked by a   
  4.     //Subject that is guaranteed authenticated  
  5.     ...  
  6. }  

@ RequiresGuest  
表明该用户需为”guest”用户 

@ RequiresPermissions  
当前用户需拥有制定权限 
Java代码   收藏代码
  1. @RequiresPermissions("account:create")  
  2. public void createAccount(Account account) {  
  3.     //this method will only be invoked by a Subject  
  4.     //that is permitted to create an account  
  5.     ...  
  6. }  

@RequiresRoles  
当前用户需拥有制定角色 

@ RequiresUser  
当前用户需为已认证用户或已记住用户 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值