`
lwx522
  • 浏览: 35154 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

shiro权限管理

阅读更多

最近做的项目需要加上权限控制, 最后选型用的是shiro,这个是用确实比较简单。配置文件说明

 

web.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
	<display-name>pscms</display-name>
	
	<!-- Spring ApplicationContext配置文件的路径,可使用通配符,多个路径用,号分隔
		此参数用于后面的Spring Context Loader -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			classpath*:/applicationContext*.xml
		</param-value>
	</context-param>
	
	<!-- 設定Spring Context的默认Profile -->
	<context-param>
    	<param-name>spring.profiles.default</param-name>
    	<param-value>production</param-value>
	</context-param>
	
	<!--Spring的ApplicationContext 载入 -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- Filter 定义  -->
	<!-- Character Encoding filter -->
	<filter>
		<filter-name>encodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<!-- Shiro Security filter-->
	<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> 

	<!-- SiteMesh Web-Page Layout filter-->
	<filter>
		<filter-name>sitemeshFilter</filter-name>
		<filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>sitemeshFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
  
	<!-- Spring MVC Servlet -->
	<servlet>
		<servlet-name>springServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring-mvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>springServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	
	<servlet>
    	<servlet-name>captcha</servlet-name>
    	<servlet-class>com.surfilter.pscms.web.CaptchaController</servlet-class>
    </servlet>
    <servlet-mapping>
    	<servlet-name>captcha</servlet-name>
    	<url-pattern>/captcha</url-pattern>
    </servlet-mapping>

	<!-- session超时定义,单位为分钟 -->
	<session-config>
		<session-timeout>20</session-timeout>
	</session-config>
	
	<!-- 出错页面定义 -->
	<error-page>
		<exception-type>java.lang.Throwable</exception-type>
		<location>/WEB-INF/views/error/500.jsp</location>
	</error-page>
	<error-page>
		<error-code>500</error-code>
		<location>/WEB-INF/views/error/500.jsp</location>
	</error-page>
	<error-page>
		<error-code>404</error-code>
		<location>/WEB-INF/views/error/404.jsp</location>
	</error-page>
</web-app>

 

 

 

 

 applicationContext-shiro.xml

<?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/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"
	default-lazy-init="true">

	<description>Shiro Configuration</description>

	<!-- Shiro's main business-tier object for web-enabled applications -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="shiroDbRealm" />
		<property name="cacheManager" ref="cacheManager" />
	</bean>

	<!-- 項目自定义的Realm -->
	<bean id="shiroDbRealm" class="com.surfilter.pscms.service.account.ShiroDbRealm"  depends-on="userDao,groupDao">
		<property name="accountManager" ref="accountManager"/>
	</bean>

	<!-- Shiro Filter -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<property name="loginUrl" value="/loginpw" />
		<property name="successUrl" value="/main/" />
		<property name="filters"> 
            <map> 
                <entry key="authc" value-ref="authc"></entry> 
            </map>
        </property>
		<property name="filterChainDefinitions">
			<value>
				/loginpw = authc
				/logout = logout
				/captcha = anon
				/static/** = anon
				/mobile/** = anon
		    	/** = user
		 	</value>
		</property>
	</bean>
	
	<bean id="authc" class="com.surfilter.pscms.service.captcha.CaptchaFormAuthenticationFilter"></bean>
	
	
	<!-- 用户授权信息Cache -->
	<bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />
	
	<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
	
	<!-- AOP式方法级权限检查  -->
	<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>

 

spring-mvc.xml

<?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:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

	<!-- 自动扫描且只扫描@Controller -->
	<context:component-scan base-package="com.surfilter.pscms" use-default-filters="false">
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>
	<bean id="permission" class="com.surfilter.pscms.entity.account.Permission" init-method="initialize"/> 
	<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">  
		<property name="messageConverters">   
			<list>   
				<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />  
				<bean class="org.springframework.http.converter.StringHttpMessageConverter">   
					<property name="supportedMediaTypes">   
						<list><value>text/plain;charset=UTF-8</value></list>   
					</property>   
				</bean>   
				<bean class="org.springframework.http.converter.ResourceHttpMessageConverter" />   
				<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />  
				<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter" />  
				<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" />  
			</list>   
		</property>   
	</bean>
	<mvc:annotation-driven />
	<mvc:default-servlet-handler/>
	
	<!-- 定义首页 -->
	<mvc:view-controller path="/" view-name="redirect:/main/"/>

	<!-- 定义JSP --> 
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/"/>
		<property name="suffix" value=".jsp"/>
	</bean>
	<!-- View resolvers can also be configured with ResourceBundles or XML files.    
        If you need different view resolving based on Locale, you have to use the    
        resource bundle resolver. -->   
    <!-- 这个是针对返回视图还是json值的视图配置   来分别处理同步和异步请求 -->   
    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">   
         <property name="mediaTypes">   
             <map>   
                 <entry key="html" value="text/html" />   
                 <entry key="json" value="application/json" />   
             </map>   
         </property>   
         <property name="favorParameter" value="true" />   
         <property name="viewResolvers">   
             <list>   
                 <bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />   
                 <bean id="viewResolver"  
                     class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">   
                     <property name="cache" value="true" />   
                     <property name="prefix" value="" />   
                     <property name="suffix" value=".ftl" />   
                     <property name="contentType" value="text/html;charset=UTF-8"></property>   
                     <property name="requestContextAttribute" value="request" />   
                     <property name="exposeSpringMacroHelpers" value="true" />   
                     <property name="exposeRequestAttributes" value="true" />   
                     <property name="exposeSessionAttributes" value="true" />   
                 </bean>   
             </list>   
         </property>   
         <property name="defaultContentType" value="text/html" />   
    </bean>

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  
        <property name="maxUploadSize">  
            <value>10485760</value>  
        </property>  
        <property name="maxInMemorySize">  
            <value>5120</value>  
        </property>  
    </bean>  
    
	<!-- 支持 Shiro对Controller的方法级AOP安全控制 begin-->
	<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>
	
	<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">  
        <property name="exceptionMappings">  
            <props>  
                <prop key="org.apache.shiro.authz.UnauthorizedException">error/403</prop>  
            </props>  
        </property>  
    </bean>  
	<!-- end -->
	
	<!-- 初始化加载板块列表 -->
    <bean id="showBoards" class="com.surfilter.pscms.bean.ShowBoards" init-method="init"></bean>
	
</beans>

 

ShiroDbRealm.java继承AuthorizingRealm 重新认证和鉴权的方法

 

package com.surfilter.pscms.service.account;

import java.io.Serializable;

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.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import com.surfilter.pscms.entity.account.User;
import com.surfilter.pscms.service.captcha.CaptchaUsernamePasswordToken;
import com.surfilter.pscms.service.captcha.IncorrectCaptchaException;

/**
 * 自实现用户与权限查询. 演示关系,密码用明文存储,因此使用默认 的SimpleCredentialsMatcher.
 */
public class ShiroDbRealm extends AuthorizingRealm {

	private AccountManager accountManager;

	/**
	 * 认证回调函数, 登录时调用.
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		CaptchaUsernamePasswordToken token = (CaptchaUsernamePasswordToken) authcToken;
		// 验证码 验证
		String captcha = null;
		Object obj_captcha = SecurityUtils.getSubject().getSession()
				.getAttribute("RandomCode");
		if (obj_captcha instanceof String)
			captcha = (String) obj_captcha;

		if (captcha != null && !captcha.equalsIgnoreCase(token.getCaptcha())) {
			throw new IncorrectCaptchaException("验证码错误!");
		}

		// 用户名密码验证
		User user = accountManager.findUserByLoginName(token.getUsername());
		if (user != null) {
			SecurityUtils.getSubject().getSession().setAttribute(
					"loginUserInfo", user);
			return new SimpleAuthenticationInfo(new ShiroUser(user
					.getLoginName(), user.getName()), user.getPassword(),
					getName());
		} else {
			return null;
		}
	}

	/**
	 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		ShiroUser shiroUser = (ShiroUser) principals.fromRealm(getName())
				.iterator().next();
		User user = accountManager
				.findUserByLoginName(shiroUser.getLoginName());
		if (user != null) {
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
			info.addStringPermissions(accountManager.getUserPermissions(user.getId()));
			return info;
		} else {
			return null;
		}
	}

	/**
	 * 更新用户授权信息缓存.
	 */
	public void clearCachedAuthorizationInfo(String principal) {
		SimplePrincipalCollection principals = new SimplePrincipalCollection(
				principal, getName());
		clearCachedAuthorizationInfo(principals);
	}

	/**
	 * 清除所有用户授权信息缓存.
	 */
	public void clearAllCachedAuthorizationInfo() {
		Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
		if (cache != null) {
			for (Object key : cache.keys()) {
				cache.remove(key);
			}
		}
	}

	@Autowired
	public void setAccountManager(AccountManager accountManager) {
		this.accountManager = accountManager;
	}

	/**
	 * 自定义Authentication对象,使得Subject除了携带用户的登录名外还可以携带更多信息.
	 */
	public static class ShiroUser implements Serializable {

		private static final long serialVersionUID = -1748602382963711884L;
		private String loginName;
		private String name;

		public ShiroUser(String loginName, String name) {
			this.loginName = loginName;
			this.name = name;
		}

		public String getLoginName() {
			return loginName;
		}

		/**
		 * 本函数输出将作为默认的<shiro:principal/>输出.
		 */
		@Override
		public String toString() {
			return loginName;
		}

		public String getName() {
			return name;
		}
	}
}

 

jsp页面中控制权限, name为相应的权限点

<shiro:hasPermission name="dict_analysis:edit">

     相应的操作

</shiro:hasPermission>

 

控制层相应的方法用注解控制权限

@RequiresPermissions("dict_analysis:edit")

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics