shiro介紹
一、什麼是shiro
二、Apache Shiro 的架構:
1、Subject :當前用戶的操作
2、SecurityManager:用於管理所有的Subject
SecurityManager即安全管理器,對全部的subject進行安全管理,它是shiro的核心,負責對所有的subject進行安全管理。通過
SecurityManager可以完成subject的認證、授權等,實質上SecurityManager是通過Authenticator進行認證,通過Authorizer進行授權,
通過SessionManager進行會話管理等。
SecurityManager是一個接口,繼承了Authenticator, Authorizer, SessionManager這三個接口。
3、Realms:用於進行權限信息的驗證
比如:如果用戶身份數據在數據庫那麼realm就需要從數據庫獲取用戶身份信息。
注意:不要把realm理解成只是從數據源取數據,在realm中還有認證授權校驗的相關的代碼。
4、Authenticator:認證器,驗證用戶身份的過程.。
5、Authorizer:授權器,授權訪問控制。
6、sessionManager:會話管理
7、SessionDao:會話dao
8、CacheManager:緩存管理
9、Cryptography:密碼管理
三、認證流程和授權流程
四、shiro與SpringMVC整合
CREATE TABLE `sys_permission` (
`id` bigint(20) NOT NULL COMMENT '主鍵',
`name` varchar(128) NOT NULL COMMENT '資源名稱',
`type` varchar(32) NOT NULL COMMENT '資源類型:menu,菜單 permission菜單下的資源,',
`url` varchar(128) DEFAULT NULL COMMENT '訪問url地址',
`percode` varchar(128) DEFAULT NULL COMMENT '權限代碼字符串',
`parentid` bigint(20) DEFAULT NULL COMMENT '父結點id',
`parentids` varchar(128) DEFAULT NULL COMMENT '父結點id列表串',
`sortstring` varchar(128) DEFAULT NULL COMMENT '排序號',
`available` char(1) DEFAULT NULL COMMENT '是否可用,1:可用,0不可用',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1.在web.xml添加shiroFilter
<!-- shiro過慮器,DelegatingFilterProx會從spring容器中找shiroFilter -->
<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>
2.配置applicationContext-shiro.xml
並配置到web.xml的contextConfigLocation中
<!-- Shiro 的Web過濾器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<!-- 如果沒有認證將要跳轉的登陸地址,http可訪問的url,如果不在表單認證過慮器FormAuthenticationFilter中指定此地址就爲身份認證地址 -->
<property name="loginUrl" value="/login.action" />
<!-- 沒有權限跳轉的地址 -->
<property name="unauthorizedUrl" value="/refuse.jsp" />
<!-- shiro攔截器配置 -->
<property name="filters">
<map>
<entry key="authc" value-ref="formAuthenticationFilter" />
</map>
</property>
<property name="filterChainDefinitions">
<value>
<!-- 必須通過身份認證方可訪問,身份認 證的url必須和過慮器中指定的loginUrl一致 -->
/loginsubmit.action = authc
<!-- 退出攔截,請求logout.action執行退出操作 -->
/logout.action = logout
<!-- 無權訪問頁面 -->
/refuse.jsp = anon
<!-- roles[XX]表示有XX角色纔可訪問 -->
/item/list.action = roles[item],authc
/js/** anon
/images/** anon
/styles/** anon
<!-- user表示身份認證通過或通過記住我認證通過的可以訪問 -->
/** = user
<!-- /**放在最下邊,如果一個url有多個過慮器則多個過慮器中間用逗號分隔,如:/** = user,roles[admin] -->
</value>
</property>
</bean>
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userRealm" />
</bean>
<!-- 自定義 realm -->
<bean id="userRealm" class="cn.ssm.realm.CustomRealm1">
</bean>
<!-- 基於Form表單的身份驗證過濾器,不配置將也會註冊此過慮器,表單中的用戶賬號、密碼及loginurl將採用默認值,建議配置 -->
<bean id="formAuthenticationFilter"
class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
<!-- 表單中賬號的input名稱 -->
<property name="usernameParam" value="usercode" />
<!-- 表單中密碼的input名稱 -->
<property name="passwordParam" value="password" />
<!-- <property name="rememberMeParam" value="rememberMe"/> -->
<!-- loginurl:用戶登陸地址,此地址是可以http訪問的url地址 -->
<property name="loginUrl" value="/loginsubmit.action" />
</bean>
securityManager:這個屬性是必須的。loginUrl:沒有登錄認證的用戶請求將跳轉到此地址,不是必須的屬性,不輸入地址的話會自動尋找項目web項目的根目錄下的”/login.jsp”頁面。
unauthorizedUrl:沒有權限默認跳轉的頁面。
3.自定義realm
public class ActiveUser {
private String userid;//用戶id(主鍵)
private String usercode;// 用戶賬號
private String username;// 用戶名稱
private List<SysPermission> menus;// 菜單
private List<SysPermission> permissions;// 權限
public class CustomRealm1 extends AuthorizingRealm {
@Autowired
private SysService sysService;
@Override
public String getName() {
return "customRealm";
}
// 支持什麼類型的token
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof UsernamePasswordToken;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
// 從token中獲取用戶身份
String usercode = (String) token.getPrincipal();
SysUser sysUser = null;
try {
sysUser = sysService.findSysuserByUsercode(usercode);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 如果賬號不存在
if (sysUser == null) {
throw new UnknownAccountException("賬號找不到");
}
// 根據用戶id取出菜單
List<SysPermission> menus = null;
try {
menus = sysService.findMenuList(sysUser.getId());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 用戶密碼
String password = sysUser.getPassword();
//鹽
String salt = sysUser.getSalt();
// 構建用戶身體份信息
ActiveUser activeUser = new ActiveUser();
activeUser.setUserid(sysUser.getId());
activeUser.setUsername(sysUser.getUsername());
activeUser.setUsercode(sysUser.getUsercode());
activeUser.setMenus(menus);
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
activeUser, password, ByteSource.Util.bytes(salt),getName());
return simpleAuthenticationInfo;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
//身份信息
ActiveUser activeUser = (ActiveUser) principals.getPrimaryPrincipal();
//用戶id
String userid = activeUser.getUserid();
//獲取用戶權限
List<SysPermission> permissions = null;
try {
permissions = sysService.findSysPermissionList(userid);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//構建shiro授權信息
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
for(SysPermission sysPermission:permissions){
simpleAuthorizationInfo.addStringPermission(sysPermission.getPercode());
}
return simpleAuthorizationInfo;
}
}
5.添加憑證匹配器
<!-- 憑證匹配器 -->
<bean id="credentialsMatcher"
class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="md5" />
<property name="hashIterations" value="1" />
</bean>
<!-- 自定義 realm -->
<bean id="userRealm" class="cn.ssm.realm.CustomRealm1">
<property name="credentialsMatcher" ref="credentialsMatcher" />
</bean>
6.開啓對shiro註解支持
<!-- 開啓aop,對類代理 -->
<aop:config proxy-target-class="true"></aop:config>
<!-- 開啓shiro註解支持 -->
<bean
class="
org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>
在Controller中添加@RequiresPermissions("item:query")
其中item:query是數據庫中的權限代碼字符串,在授權的時候會查詢數據庫進行查找。7.配置緩存
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userRealm" />
<property name="sessionManager" ref="sessionManager" />
<property name="cacheManager" ref="cacheManager"/>
</bean>
<!-- 緩存管理器 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml"/>
</bean>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
8.配置session管理
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userRealm" />
<property name="sessionManager" ref="sessionManager" />
</bean>
<!-- 會話管理器 -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!-- session的失效時長,單位毫秒 -->
<property name="globalSessionTimeout" value="600000"/>
<!-- 刪除失效的session -->
<property name="deleteInvalidSessions" value="true"/>
</bean>
9.登錄退出
//登陸提交地址,和applicationContext-shiro.xml中配置的loginurl一致
@RequestMapping("login")
public String login(HttpServletRequest request)throws Exception{
//如果登陸失敗從request中獲取認證異常信息,shiroLoginFailure就是shiro異常類的全限定名
String exceptionClassName = (String) request.getAttribute("shiroLoginFailure");
//根據shiro返回的異常類路徑判斷,拋出指定異常信息
if(exceptionClassName!=null){
if (UnknownAccountException.class.getName().equals(exceptionClassName)) {
//最終會拋給異常處理器
throw new CustomException("賬號不存在");
} else if (IncorrectCredentialsException.class.getName().equals(
exceptionClassName)) {
throw new CustomException("用戶名/密碼錯誤");
} else if("randomCodeError".equals(exceptionClassName)){
throw new CustomException("驗證碼錯誤 ");
}else {
throw new Exception();//最終在異常處理器生成未知錯誤
}
}
//此方法不處理登陸成功(認證成功),shiro認證成功會自動跳轉到上一個請求路徑
//登陸失敗還到login頁面
return "login";
}
//系統首頁
@RequestMapping("/first")
public String first(Model model)throws Exception{
//從shiro的session中取activeUser
Subject subject = SecurityUtils.getSubject();
//取身份信息
ActiveUser activeUser = (ActiveUser) subject.getPrincipal();
//通過model傳到頁面
model.addAttribute("activeUser", activeUser);
return "/first";
}
退出:不需要寫退出,直接在shiro配置中添加,session由shiro管理。可以直接退出。10.shiro過濾器和jsp標籤
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表示需要認證(登錄)才能使用,沒有參數
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是授權過濾器
<%@ tagliburi="http://shiro.apache.org/tags" prefix="shiro" %>
標籤名稱 標籤條件(均是顯示標籤內容)
<shiro:authenticated> 登錄之後
<shiro:notAuthenticated> 不在登錄狀態時
<shiro:guest> 用戶在沒有RememberMe時
<shiro:user> 用戶在RememberMe時
<shiro:hasAnyRoles name="abc,123" > 在有abc或者123角色時
<shiro:hasRole name="abc"> 擁有角色abc
<shiro:lacksRole name="abc"> 沒有角色abc
<shiro:hasPermission name="abc"> 擁有權限資源abc
<shiro:lacksPermission name="abc"> 沒有abc權限資源
<shiro:principal> 顯示用戶身份名稱
<shiro:principal property="username"/> 顯示用戶身份中的屬性值
以上就是shiro和springmvc初步整合。