ps:
一.環境:SpringMvc+spring+Mybatis,前後端分離,只支持單臺項目(未實現單點登入);
二.需對shiro原理流程,有基礎的理解,以及用戶權限需求的應用場景明瞭,能更好項目整合;
三.shiro的基本構成:
1.Subject (接口) : 主體(當前用戶) 定義了認證授權的相關函數,通過SecurityManage 安全管理器進行授權按認證
2.SecurityManage (接口) : 框架核心核心 安全管理器,對subject進行認證,授權
3.Authenticator : 認證器,對主體進行認證(登入)
4.Authorizer : 授權器,通過認證後,在訪問功能接口時,通過授權器判斷用戶是否有該功能的操作權限
5.Realm : 讀取用戶權限數據, 進行安全認證需要通過realm,獲取用戶權限數據
6.SessionManage : 會話管理器,自定義了一套,不依賴http的session
7.SessionDAO : 操作會話信息,例如將會話信息存儲到redis庫
8.CacheManage : 緩存管理器 ,將用戶權限數據存儲在緩存
9.Cryptography : 加密
demo
1.maven依賴:
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.4.1</version> </dependency> <dependency> <groupId>org.ehcache</groupId> <artifactId>ehcache</artifactId> <version>3.8.0</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.1</version> </dependency>
2.spring整合shiro配置:
1)spring.xml <!--自定義的relam--> <bean name="shiroRealm" class="hotkidclub.shiro.ShiroRealm"/> <!--緩存管理器--> <bean name="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"/> <!--shiro安全管理器--> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="shiroRealm"/> <property name="cacheManager" ref="shiroCacheManager"/> </bean> <!-- 啓動安全管理器: 相當於調用SecurityUtils.setSecurityManager(securityManager) --> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/> <property name="arguments" ref="securityManager"/> </bean> <!-- shiro 的Web過濾器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <!--如果沒有認證將要跳轉的登陸地址 --> <property name="loginUrl" value="/login"/> <!-- 配置安全規則:1). anon 可以被匿名訪問 2). authc 必須認證(即登錄)後纔可能訪問的頁面 --> <property name="filterChainDefinitions"> <value> <!-- 登錄不攔截 --> / = anon /static/** = anon /login.ctrl = anon /** = authc </value> </property> </bean> <!-- 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> <!-- Shiro生命週期處理器--> <bean name="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
2)web.xml
<!-- shiro過慮器 --> <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>*.ctrl</url-pattern> </filter-mapping>
<!-- 接收接口請求適配器 --> <servlet> <servlet-name>backend_shiro_demo</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value></param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>backend_shiro_demo</servlet-name> <url-pattern>*.ctrl</url-pattern> </servlet-mapping>
3).自定義shiro的realm
package hotkidclub.shiro; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.session.Session; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; public class ShiroRealm extends AuthorizingRealm { /** * 認證器 : * <p> * 本平臺用戶登入接口調用-subject.login() : 回調該函數 * </p> * * @param authcToken 憑證信息:可存放用戶賬號密碼 * @return 認證信息:包含當前請求登入的用戶信息 * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { System.out.println("認證開始"); Subject subject = SecurityUtils.getSubject(); // 1.獲取認證的主體信息:賬戶密碼...,TODO authcToken轉換爲本平臺業務bean UsernamePasswordToken token = (UsernamePasswordToken) authcToken; // 2.對比數據庫存儲的賬號密碼 // 3.創建簡單認證信息對象 : new SimpleAuthenticationInfo(object, object, 字符串);可傳遞自定義對象,字符內容; Session session = subject.getSession(); session.setAttribute("user", token.getPrincipal()); SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(token.getPrincipal(), token.getCredentials(), getName()); return info; } /** * 授權器 : 校驗用戶的角色和權限 * <p> * 本平臺接口配置角色/權限的授權註解時 : 回調該函數 * </p> * * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { // TODO 1.通過用戶名去數據庫查詢該用戶有哪些角色和權限 // TODO 2.設置角色信息 // TODO 3.設置權限信息 // 創建簡單授權信息對象 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addRole("admin"); info.addStringPermission("add"); System.out.println("鑑權完成"); return info; } }
3.測試
//登入
@ResponseBody
@PostMapping(value = "/login.ctrl", produces = "application/json")
public Map<String, Object> login(@RequestBody Map<String, Object> params, HttpSession httpSession) {
Object object = null;
// shiro login
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(賬號,密碼 );
subject.login(token);
object = result;
return object;
}
/**
* 測試:角色/權限的核查
*
* @param session
* @return
*/
@ResponseBody
@RequiresRoles(value = "admin")//鑑查角色註解
@RequiresPermissions(value = "add")//鑑權註解
@GetMapping(value = "/check.ctrl", produces = "application/json") // @RequiresPermissions (value={"add", "update"}, logical= Logical.OR)
public Map<String, Object> permission(HttpSession session) {
String object = null;try {
Subject subject = SecurityUtils.getSubject();
object = "ok";
}
return object;
}