一 配置shiro的filter實現URL級別權限控制
登錄流程:應用程序-->Subject(就是shiro管理的用戶)-->securityManger(安全管理器,shiro權限控制的核心)--Realm(應用程序和安全數據之間連接器)--安全數據---->SecurityManager(底層判斷)---->Suject--->application code
在編寫程序是操作Subject方法,調用底層的SucurityManger安全管理器進行管理,並通過Realm這個應用程序和安全數據之間的連接器的對象,來完成權限控制讀取安全數據.
1.配置web.xml

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <!-- spring配置文件位置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- spring核心監聽器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- shiro的filter --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- struts2 過濾器 --> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping> </web-app>
2.配置application.xml
anon 未認證可以訪問 authc 認證后可以訪問 perms 需要特定權限才能訪問 roles 需要特定角色才能訪問
user 需要特定用戶才能訪問 port 需要特定端口才能訪問 reset 根據指定 HTTP 請求訪問才能訪問

<?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控制過濾器規則 --> <property name="filterChainDefinitions"> <value> /login.html* =anon /user_login.action=anon <!-- 登錄時在認證前訪問 --> /validatecode.jsp*=anon <!-- anon 未認證可訪問.authc認證后可訪問--> /css/**=anon /js/**=anon /images/**=anon /services/**=anon /**=authc </value> </property> </bean> <!-- 安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="bosRealm"></property> </bean> <!-- shiro的后處理器 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"> </bean> </beans>
3.在登錄界面,form表單補全,並提交.
<form class="form-horizontal" id="loginform" name="loginform" method="post" action="user_login.action">
<a href="javascript:$('#loginform').submit();" id="loginform" name="loginform" >立即登錄</a>
4.在UserAction編寫login方法

package cn.itcast.bos.web.action.system; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Namespace; import org.apache.struts2.convention.annotation.ParentPackage; import org.apache.struts2.convention.annotation.Result; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import cn.itcast.bos.domain.system.User; import cn.itcast.bos.web.action.common.BaseAction; @Namespace("/") @Controller @ParentPackage("json-default") @Scope("prototype") public class UserAction extends BaseAction<User>{ @Action(value="user_login",results={@Result(type="redirect",name="success",location="index.html") ,@Result(name="login",type="redirect",location="login.html")}) public String login(){ //用戶名和密碼都保存在model中 //基於shiro實現登錄 Subject subject = SecurityUtils.getSubject(); //用戶名和密碼保存到token中 AuthenticationToken token= new UsernamePasswordToken(model.getUsername(),model.getPassword()); try { //如果正常登錄,表示沒有異常.登陸成功 subject.login(token); return SUCCESS; } catch (Exception e) { //如果異常,表示登錄失敗,重新跳轉到登錄頁面 e.printStackTrace(); return LOGIN; } } }
5.定義Realm,實現認證方法.

package cn.itcast.bos.realm; 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.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.stereotype.Component; import cn.itcast.bos.domain.system.User; import cn.itcast.bos.service.system.UserService; //加入Spring管理的注解,bean管理. @Component("bosRealm") public class BosRealm extends AuthorizingRealm{ private UserService userService ; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) { System.out.println("授權..."); return null; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("認證..."); //轉換token UsernamePasswordToken UsernamePasswordToken=(UsernamePasswordToken) token; //根據用戶名查詢用戶信息 User user = userService.findByUsername(UsernamePasswordToken.getUsername()); if(user==null){ //用戶名不存在 //參數一:期望登陸后保存在subject中的信息 //參數二:密碼 //參數三:realm的名稱 //return new SimpleAuthenticationInfo(user,null,getName()); return null; }else{ //用戶名存在 //當返回密碼時,securityManager安全管理器會自動比較與用戶傳過來的密碼 //如果一致,登陸成功,如果不一致,報密碼錯誤異常 return new SimpleAuthenticationInfo(user,user.getPassword(),getName()); } } }
6.調用service與dao
package cn.itcast.bos.service.system; import cn.itcast.bos.domain.system.User; public interface UserService { public User findByUsername(String username); }
package cn.itcast.bos.service.system.impl; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import cn.itcast.bos.dao.system.UserRepository; import cn.itcast.bos.domain.system.User; import cn.itcast.bos.service.system.UserService; @Service @Transactional public class UserServiceImpl implements UserService { private UserRepository userRepository ; @Override public User findByUsername(String username) { return userRepository.findByUsername(username); } }
package cn.itcast.bos.dao.system; import org.springframework.data.jpa.repository.JpaRepository; import cn.itcast.bos.domain.system.User; public interface UserRepository extends JpaRepository<User, Integer>{ public User findByUsername(String username); }
org.apache.shiro.authc.UnknownAccountException 當認證方法直接返回 null,說明用戶名不存在
org.apache.shiro.authc.IncorrectCredentialsException 當返回對象中密碼與用戶輸入密碼不一致 密碼錯誤