shiro許可權框架詳解06-shiro與web專案整合(上)
shiro和web專案整合,實現類似真實專案的應用
本文中使用的專案架構是springMVC+mybatis,所以我們是基於搭建好的專案進行改造的。
- 將shiro整合到web應用中
- 登入
- 退出
- 認證資訊在頁面展現,也就是顯示選單
- shiro的過濾器
將shiro整合到web應用中
資料庫腳步
sql腳步放到專案中,專案上傳到共享的資源中,文章最後給出共享url。
去除專案中不使用shiro實現認證的攔截器
<!--攔截器 -->
<!-- <mvc:interceptors> <mvc:interceptor> -->
<!-- 使用者認證攔截 -->
<!-- <mvc:mapping path="/**" /> <bean class="cn.itcast.ssm.controller.interceptor.LoginInterceptor"></bean>
</mvc:interceptor> <mvc:interceptor> -->
<!-- 授權攔截 -->
<!-- <mvc:mapping path="/**" /> <bean class="cn.itcast.ssm.controller.interceptor.PermissionInterceptor"></bean>
</mvc:interceptor> </mvc:interceptors> -->
新增shiro的jar包
除了前面文章提到的shiro-core相關的jar包,還需要如下:
- 與web整合的 shiro-web-1.2.3.jar
- 與spring整合的 shiro-spring-1.2.3.jar
- 與ehcache整合的 shiro-ehcache-1.2.3.jar
在web.xml中配置shiro的filter
在web系統中,shiro 也是通過filter進行攔截的。filter攔截後將操作交給filterChain(過濾器煉)。shiro中提供了多個filter,在欄目 shiro的過濾器 會全部介紹
在web中配置filter,如下:
<!--shirofilter-->
<!-- shiro過濾器,DelegatingFilterProxy通過代理模式將spring容器的bean和filter關聯起來 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<!--設定true由servlet容器控制filter的生命週期-->
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
<!--設定spring容器filter的bean id,如果不設定則找與filter-name一致的bean -->
<init-param>
<param-name>targetBeanName</param-name>
<param-value>shiroFilter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
新建applicationContext-shiro.xml檔案
內容下圖:
<!-- web.xml中shiro的filter對應的bean -->
<!-- shiro的web過濾器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<!-- logiUrl認證提交地址,如果沒有認證通過將會請求此地址進行認證,請求此地址將由formAuthenticationFilter進行表單認證 -->
<property name="loginUrl" value="/login.action" />
<!-- 認證成功後統一跳轉到first.action,建議不配置,shiro認證成功自動到上一個連結 -->
<property name="successUrl" value="/first.action" />
<!-- 通過unauthorizedUrl指定沒有許可權時跳轉頁面 -->
<property name="unauthorizedUrl" value="/refuse.jsp" />
<!-- 過濾器鏈定義,從上向下順序執行,一般將/**放在最後面 -->
<property name="filterChainDefinitions">
<value>
<!--靜態資源可以匿名訪問 -->
/images/** = anon
/js/** = anon
/styles/** = anon
<!--登入驗證碼匿名訪問-->
/validatecode.jsp = anon
<!--任何連結都可以不認證訪問-->
/** = anon
</value>
</property>
</bean>
<!--securityManager安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="customRealm" />
</bean>
<!-- 自定義的realm -->
<bean id="customRealm" class="cn.itcast.ssm.shiro.CustomRealm"/>
上面配置的CustomRealm
的內容和文章shiro許可權框架詳解05-shiro授權的CustomRealm一樣。
測試是否整合成功
在介面輸入CustomRealm
程式碼中的賬號為 zhangsan 密碼為 123 可以進入歡迎頁面。
但是並沒有選單和相關使用者資訊
登入功能
原理
由於登入使用的是 org.apache.shiro.web.filter.authc.FormAuthenticationFilter
filter實現的,具體流程如下:
如果使用者沒有認證時,請求上面配置的loginUrl進行認證,使用者的身份資訊和密碼提交到loginUrl,FormAuthenticationFilter攔截取出request中的username和password(引數的key是可以進行配置的,下一篇blog介紹)引數值。FormAuthenticationFilter呼叫realm傳入一個token(包含username和password),realm根據username查詢使用者資訊,如果查詢不到,返回null,FormAuthenticationFilter向request域中填充一個引數,key為shiroLoginFailure
記錄異常資訊。如果不為空的話,返回AuthenticationInfo
類。
修改登入頁面
由於FormAuthenticationFilter的身份資訊和密碼的請求引數的key預設是(username和password),修改login.jsp頁面的賬號和密碼輸入框name屬性值,並註釋掉驗證碼的程式碼。
修改controller類
修改LoginController
的 login
方法如下:
@RequestMapping("/login")
public String login(HttpServletRequest request)throws Exception{
//如果登入失敗從request中獲取認證異常資訊,shiroLoginFailure就是shiro異常類的全限定名
String exceptionClassName = (String) request.getAttribute("shiroLoginFailure");
if(exceptionClassName!=null){
if(UnknownAccountException.class.getName().equals(exceptionClassName)){
throw new CustomException("賬號不存在");
}else if(IncorrectCredentialsException.class.getName().equals(exceptionClassName)){
throw new CustomException("使用者名稱或密碼錯誤");
}else {
throw new Exception();//最終在異常處理器生成未知錯誤
}
}
//此方法不處理登入成功(認證成功),shiro認證成功會自動跳轉到上一個請求路徑。
//登入失敗還到login頁面
return "login";
}
這個方法只有校驗不通過的時候才會執行。真正的校驗方法是在自定義的realm中,校驗身份是否正確。
修改認證攔截器
將所有請求都改為需要認證才能訪問的。
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<!-- logiUrl認證提交地址,如果沒有認證通過將會請求此地址進行認證,請求此地址將由formAuthenticationFilter進行表單認證 -->
<property name="loginUrl" value="/login.action" />
<!-- 認證成功後統一跳轉到first.action,建議不配置,shiro認證成功自動到上一個連結 -->
<property name="successUrl" value="/first.action" />
<!-- 通過unauthorizedUrl指定沒有許可權時跳轉頁面 -->
<property name="unauthorizedUrl" value="/refuse.jsp" />
<!-- 自定義filter配置 -->
<property name="filters">
<map>
<entry key="authc" value-ref="formAuthenticationFilter"/>
</map>
</property>
<!-- 過濾器鏈定義,從上向下順序執行,一般將/**放在最後面 -->
<property name="filterChainDefinitions">
<value>
<!--靜態資源可以匿名訪問 -->
/images/** = anon
/js/** = anon
/styles/** = anon
/validatecode.jsp = anon
<!-- /**=authc 表示所有的url都需要認證才能訪問 -->
/** = authc
</value>
</property>
</bean>
驗證登入功能
在登入介面輸入賬號為 zhangsan 密碼為 123 驗證是否登入成功,然後輸入錯誤的賬號,控制檯出現下面的異常資訊:
如果輸入密碼錯誤:
異常資訊和前面Java專案演示的一樣。
退出
退出不需要我們自己實現,只要去訪問一個退出的url(該url是可以不存在的)即可,由LogoutFilter filter處理,清除session。在applicationContext.xml配置logoutFilter
<!-- web.xml中shiro的filter對應的bean -->
<!-- shiro的web過濾器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<!-- logiUrl認證提交地址,如果沒有認證通過將會請求此地址進行認證,請求此地址將由formAuthenticationFilter進行表單認證 -->
<property name="loginUrl" value="/login.action" />
<!-- 認證成功後統一跳轉到first.action,建議不配置,shiro認證成功自動到上一個連結 -->
<property name="successUrl" value="/first.action" />
<!-- 通過unauthorizedUrl指定沒有許可權時跳轉頁面 -->
<property name="unauthorizedUrl" value="/refuse.jsp" />
<!-- 自定義filter配置 -->
<property name="filters">
<map>
<entry key="authc" value-ref="formAuthenticationFilter"/>
</map>
</property>
<!-- 過濾器鏈定義,從上向下順序執行,一般將/**放在最後面 -->
<property name="filterChainDefinitions">
<value>
<!--靜態資源可以匿名訪問 -->
/images/** = anon
/js/** = anon
/styles/** = anon
/validatecode.jsp = anon
<!-- 請求logout.action地址,shiro去清除session -->
/logout.action = logout
<!-- /**=authc 表示所有的url都需要認證才能訪問 -->
/** = authc
</value>
</property>
</bean>
刪除原來的退出方法。
選單顯示
修改realm從資料庫查詢使用者資訊及使用者擁有的選單設定在AuthenticatorInfo中。具體程式碼如下:
/**
* 用於認證
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
//第一步:通過token獲取身份資訊
String userCode = (String) token.getPrincipal();
if (!"zhangsan".equals(userCode)) {// 這裡模仿查詢不到
return null;
}
String password = "123";
//模擬資料activeUser就是使用者身份資訊
ActiveUser activeUser = new ActiveUser();
activeUser.setUserid("zhangsan");
activeUser.setUsercode("zhangsan");
activeUser.setUsername("張三");
//查詢選單資訊
List<SysPermission> menus = null;
try {
menus = sysService.findMenuListByUserId(activeUser .getUsercode());
} catch (Exception e) {
e.printStackTrace();
}
activeUser.setMenus(menus);
//如果查詢到結果返回AuthenticationInfo
AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(activeUser, password, "");
return authenticationInfo;
}
上面的程式碼通過模擬從資料庫獲取資料設定到ActiveUser中。
修改FirstAction中的first方法
修改程式碼將獲取身份資訊,並放入request域中用於頁面顯示。
//系統首頁
@RequestMapping("/first")
public String first(Model model)throws Exception{
Subject subject =SecurityUtils.getSubject();
ActiveUser activeUser = (ActiveUser)subject.getPrincipal();
model.addAttribute("activeUser", activeUser);
return "/first";
}
測試
在登入介面,賬號輸入 zhangsan , 密碼輸入 123
如果成功的話,將會看到如下頁面。
shiro過濾器總結
過濾器簡稱 | 對應的Java類 |
---|---|
anon | org.apache.shiro.web.filter.authc.AnonymousFilter |
authc | org.apache.shiro.web.filter.authc.FormAuthenticationFilter |
authcBasic | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter |
perms | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter |
port | org.apache.shiro.web.filter.authz.PortFilter |
rest | org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter |
roles | org.apache.shiro.web.filter.authz.RolesAuthorizationFilter |
ssl | org.apache.shiro.web.filter.authz.SslFilter |
user | org.apache.shiro.web.filter.authc.UserFilter |
logout | org.apache.shiro.web.filter.authc.LogoutFilter |
各個過濾器的介紹和作用:
anon:例子/admins/**=anon
沒有引數,表示可以匿名使用。
authc:例如/admins/user/**=authc
表示需要認證(登入)才能使用,FormAuthenticationFilter是表單認證,沒有引數 。
roles:例子 /admins/user/** =roles[admin]
,引數可以寫多個,多個時必須加上引號,並且引數之間用逗號分割,當有多個引數時,例如admins/user/** =roles["admin,guest"]
,每個引數通過才算通過,相當於hasAllRoles()方法。
perms:例子/admins/user/**=perms[user:add:*]
,引數可以寫多個,多個時必須加上引號,並且引數之間用逗號分割,例如/admins/user/**=perms["user:add:*,user:modify:*"]
,當有多個引數時必須每個引數都通過才通過,想當於isPermitedAll()方法。
rest:例子/admins/user/**=rest[user]
,根據請求的方法,相當於/admins/user/**=perms[user:method]
,其中method為post,get,delete等。
port:例子/admins/user/**=port[8081]
,當請求的url的埠不是8081是跳轉到schemal://serverName:8081?queryString
,其中schmal是協議http或https等,serverName是你訪問的host,8081是url配置裡port的埠,queryString
是你訪問的url裡的?後面的引數。
authcBasic:例如/admins/user/**=authcBasic
沒有引數表示httpBasic認證
ssl:例子/admins/user/**=ssl沒有引數,表示安全的url請求,協議為https
user:例如/admins/user/**=user沒有引數表示必須存在使用者, 身份認證通過或通過記住我認證通過的可以訪問,當登入操作時不做檢查
注:
anon,authcBasic,auchc,user是認證過濾器,
perms,roles,ssl,rest,port是授權過濾器
blog的專案地址
點選進入下載頁面