1. 程式人生 > >shiro-springmvc-mybatis登入認證 許可權控制

shiro-springmvc-mybatis登入認證 許可權控制

最近閒的沒事研究了一下shiro,整合springmvc-mybatis-maven做了一個簡單的登入認證許可權控制:

1:shiro jar

<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-core</artifactId>
			<version>1.2.3</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.2.3</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-cas</artifactId>
			<version>1.2.3</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-web</artifactId>
			<version>1.2.3</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-ehcache</artifactId>
			<version>1.2.3</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-quartz</artifactId>
			<version>1.2.3</version>
		</dependency>
	
2:shiro 配置檔案:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd">

	<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.cat.shiro.ShiroRealm">
		<property name="cacheManager" ref="cacheManager" />
	</bean>

	<!-- Shiro Filter -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<property name="successUrl" value="/govern/pages/member/index" />
		<property name="loginUrl" value="/govern/pages/login" />
		<property name="unauthorizedUrl" value="/govern/pages/err" />
		<!-- <property name="filters">
			<map>
				<entry key="authc" value-ref="shiro"></entry>
			</map>
		</property> -->
		<property name="filterChainDefinitions">
			<value>
				<!-- 靜態資源允許訪問 -->
				<!-- anon 允許訪問 -->
				/login/logincs.do = anon
				/login/submitcs.do = anon
				<!-- authc需要授權 -->
				/** = authc
			</value>
		</property>
	</bean>
	<!-- <bean id="shiro" class="com.cat.shiro.ShiroFilter">

	</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>

3:web.xml 對應配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:conf/shiro.xml
</param-value>
</context-param>
<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>  


4:springmvc.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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
            http://www.springframework.org/schema/mvc 
            http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd 
            http://www.springframework.org/schema/context 
            http://www.springframework.org/schema/context/spring-context-3.0.xsd 
            http://www.springframework.org/schema/aop 
            http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
            http://www.springframework.org/schema/tx 
            http://www.springframework.org/schema/tx/spring-tx-3.0.xsd ">

	<!-- 載入包中的controller 註解掃描包 -->
	<context:component-scan base-package="com.hnust.controller">
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
	</context:component-scan>
	
	<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
	<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />

	<!--配置攔截器, 多個攔截器,順序執行 -->
	<!-- 匹配的是url路徑 -->
	<!-- <mvc:mapping path="/user/**" /> <mvc:mapping path="/test/**" /> -->
	<!-- 當設定多個攔截器時,先按順序呼叫preHandle方法,然後逆序呼叫每個攔截器的postHandle和afterCompletion方法 -->
	<!-- 測試shiro許可權控制 暫時去掉自帶的許可權控制 <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/*/*" /> <bean 
		class="com.hnust.interceptor.LoginInterceptor"></bean> </mvc:interceptor> </mvc:interceptors> -->
	<!-- 靜態資源的訪問 -->
	<!-- 檢視分解器 -->
	<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/govern/" />
		<property name="suffix" value=".jsp" />
	</bean>
	<!-- 國際化的訊息資原始檔(本系統中主要用於顯示/錯誤訊息定製) -->
	<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
		<property name="basenames">
			<list>
				<!-- 在web環境中一定要定位到classpath 否則預設到當前web應用下找 -->
				<value>classpath:/messages</value>
			</list>
		</property>
		<property name="useCodeAsDefaultMessage" value="false" />
		<property name="defaultEncoding" value="UTF-8" />
		<property name="cacheSeconds" value="60" />
	</bean>


	<!-- 避免IE在ajax請求時,返回json出現下載 -->
	<bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
		<property name="supportedMediaTypes">
			<list>
				<value>text/html;charset=UTF-8</value>
			</list>
		</property>
	</bean>

	<!-- 上傳檔案的解析器 -->
	<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<property name="defaultEncoding" value="utf-8" />
		<property name="maxUploadSize" value="10485760000" />
		<property name="maxInMemorySize" value="40960" />
	</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.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
		<property name="exceptionMappings">
			<props>
				<prop key="org.apache.shiro.authz.UnauthorizedException">405</prop>
				<prop key="java.lang.Throwable">405</prop>
			</props>
		</property>
	</bean> 

</beans>  

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


	<!-- 引入jdbc配置檔案 -->
	<context:property-placeholder location="classpath:conf/jdbc.properties" />
	<context:annotation-config />

	<!-- 使用Annotation自動註冊Bean,解決事物失效問題:在主容器中不掃描@Controller註解,在SpringMvc中只掃描@Controller註解。 -->
	<!-- 掃描service、dao元件 --> <!-- base-package 如果多個,用“,”分隔 -->
	<context:component-scan base-package="com.hnust">
		<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
	</context:component-scan>

	<!-- 分解配置 jdbc.properites -->
	<!-- 資料來源c3p0 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="${driverClassName}" />
		<property name="url" value="${url}" />
		<property name="username" value="${username}" />
		<property name="password" value="${password}" />
		<!-- <property name="maxPoolSize" value="${c3p0.pool.size.max}" /> <property name="minPoolSize" value="${c3p0.pool.size.min}" 
			/> <property name="initialPoolSize" value="${c3p0.pool.size.ini}" /> <property name="acquireIncrement" 
			value="${c3p0.pool.size.increment}" /> -->
	</bean>
	<!-- sessionFactory 將spring和mybatis整合 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="configLocation" value="classpath:conf/mybatis-config.xml" />
		<property name="mapperLocations" value="classpath:mapper/*.xml" />    <!-- 載入mapper檔案 -->
	</bean>

	<!-- 注入工具類 -->
	<bean id="baseDao" class="com.hnust.base.BaseDao">
		<property name="sqlSessionFactory">
			<ref bean="sqlSessionFactory" />
		</property>
	</bean>
	<!-- 事務 -->
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>
	<tx:advice id="txAdvice" transaction-manager="txManager">
		<tx:attributes>
			<tx:method name="insert*" propagation="REQUIRED" />
			<tx:method name="update*" propagation="REQUIRED" />
			<tx:method name="delete*" propagation="REQUIRED" />
			<tx:method name="find" read-only="true" />
			<tx:method name="get" read-only="true" />
			<tx:method name="*" propagation="REQUIRED" />
		</tx:attributes>
	</tx:advice>
	<aop:config>
		<aop:pointcut expression="execution(* com.hnust.service.impl.*.*(..))" id="pointCut" />
		<aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut" />
	</aop:config>
	
</beans>
6:上面說的是配置檔案下面貼一下 java程式碼:

當前貼出來的類對應 上面2 配置檔案

pojo類就不貼了 我這裡沒連資料  只是模擬的使用者登入 和手動新增的許可權

/**
 * 
 */
package com.cat.shiro;

import java.util.ArrayList;
import java.util.List;

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.AuthorizationException;
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 com.cat.spring.entity.Role;
import com.cat.spring.entity.User;

/**
 */
public class ShiroRealm extends AuthorizingRealm {
	/*
	 * 授權
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		// 根據使用者配置使用者與許可權
		if (principals == null) {
			throw new AuthorizationException(
					"PrincipalCollection method argument cannot be null.");
		}
		String name = (String) getAvailablePrincipal(principals);
		List<String> roles = new ArrayList<String>();
		// 簡單預設一個使用者與角色,實際專案應User user = userService.getByAccount(name);
		// 根據使用者名稱查詢出使用者 判斷使用者資訊的有效性 然獲取使用者的角色許可權 授權
		User user = new User("shiro", "123456");
		if (user.getName().equals(name)) {
			// 模擬三個角色
			for (int x = 0; x < 3; x++) {
				roles.add("user" + x);
			}
		} else {
			throw new AuthorizationException();
		}
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		// 增加角色
		// 取出所有角色授權
		info.addRoles(roles);
		// 取出所有許可權授權
		// info.addStringPermissions(permissions);
		// 模擬擁有的許可權
		info.addStringPermission("cp:updatecs,updatecs1");
		return info;
	}

	/*
	 * 認證登入
	 */
	@SuppressWarnings("unused")
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		// 簡單預設一個使用者,實際專案應User user =
		// userService.getByAccount(token.getUsername());
		User user = new User("shiro", "123456");
		if (user == null) {
			throw new AuthorizationException();
		}
		SimpleAuthenticationInfo info = null;
		if (user.getName().equals(token.getUsername())) {
			info = new SimpleAuthenticationInfo(user.getName(),
					user.getPassword(), getName());
		}
		return info;
	}
}

7:logincontroller
package com.hnust.controller;
@Controller
@RequestMapping(value = "/login")
public class LoginController {


	/*****************測試shiro************************************/
	
	@RequestMapping(value = "/logincs", method = RequestMethod.GET)
	public String logincs() {
		return "/pages/login";
	}

	@RequestMapping(value = "/submitcs", method = RequestMethod.POST)
	public String submitcs(String username, String password) {
		User user = new User("shiro", "123456");
		try {
			// 如果登陸成功
			if (user.getName().equals(username)
					&& user.getPassword().equals(password)) {
				UsernamePasswordToken token = new UsernamePasswordToken(
						user.getName(), user.getPassword().toString());
				Subject subject = SecurityUtils.getSubject();
				subject.login(token);
				return "/pages/member/index";
			} else {
				return "/pages/login";
			}
		} catch (Exception e) {
			e.printStackTrace();
			return "/pages/login";
		}

	}
	

}

8:測試許可權類 對應上面6 類裡面設定的許可權訪問URL
package com.hnust.controller;

@Controller
@RequestMapping(value = "/cp")
public class CompanyController extends BaseController{

	
	/**
	 * updatecs
	 */
	@RequiresPermissions("cp:updatecs")
	@RequestMapping(value="/updatecs",method=RequestMethod.GET)
	public String updatecs(){
		System.err.println("成功1");
		return "index";
	}
	/**
	 * updatecs
	 */
	@RequiresPermissions("cp:updatecs1")
	@RequestMapping(value="/updatecs1",method=RequestMethod.GET)
	public String updatecs1(){
		System.err.println("成功2");
		return "index";
	}
	
	/**
	 * updatecs   這個我沒用給當前使用者新增許可權  是會提示無許可權的
	 */
	@RequiresPermissions("cp:updatecs2")
	@RequestMapping(value="/updatecs2",method=RequestMethod.GET)
	public String updatecs2(){
//		System.err.println("失敗");
		return "index";
	}

}

9:下面貼出 效果圖

登入不做許可權驗證:



登入成功:


下面開始進行許可權認證:

這是我當前角色有的許可權 所以去到了我指定的頁面


下面進行 沒有許可權的URL訪問:


好了這就完事了: 新手發帖大神勿噴