javascript
Springboot整合shiro基于url身份认证和授权认证
你還不會shiro嗎?
- 前奏
- shiro核心配置文件(rolesFilter可選)。
- 身份認證
- 多表登錄源如何操作?
- 授權管理
- 如何解決界面多角色/資源問題
- 訪問效果
權限管理在日常開發中很重要,所以硬著頭皮也要啃下來。
實現功能:
- 身份認證
- 對不同頁面進行url授權
- 多表登錄解決
- 同一個頁面多role訪問
項目完整github地址 歡迎star
springboot一些學習整合完整地址
shiro的四大組件:
- 身份認證(Authentication)-證明用戶身份,通常叫做登陸(login)。
- 授權(Authorization)-訪問控制
- 加密(Cryptography)-保護或隱藏數據
- 會話管理(session management)每個用戶時間敏感狀態
三個核心組件:Subject, SecurityManager 和 Realms.
- Subject:即“當前操作用戶”。但是,在Shiro中,Subject這一概念并不僅僅指人,也可以是第三方進程、后臺帳戶(Daemon Account)或其他類似事物。它僅僅意味著“當前跟軟件交互的東西”。但考慮到大多數目的和用途,你可以把它認為是Shiro的“用戶”概念。
Subject代表了當前用戶的安全操作,SecurityManager則管理所有用戶的安全操作。 - SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通過SecurityManager來管理內部組件實例,并通過它來提供安全管理的各種服務。
- Realm: Realm充當了Shiro與應用安全數據間的“橋梁”或者“連接器”。也就是說,當對用戶執行認證(登錄)和授權(訪問控制)驗證時,Shiro會從應用配置的Realm中查找用戶及其權限信息。
從這個意義上講,Realm實質上是一個安全相關的DAO:它封裝了數據源的連接細節,并在需要時將相關數據提供給Shiro。當配置Shiro時,你必須至少指定一個Realm,用于認證和(或)授權。配置多個Realm是可以的,但是至少需要一個。 - Shiro內置了可以連接大量安全數據源(又名目錄)的Realm,如LDAP、關系數據庫(JDBC)、類似INI的文本配置資源以及屬性文件等。如果缺省的Realm不能滿足需求,你還可以插入代表自定義數據源的自己的Realm實現。
Shiro內置過濾器,可以實現權限相關的攔截器
-
常用的過濾器:
-
anon: 無需認證(登錄)可以訪問
-
authc: 必須認證才可以訪問
-
user: 如果使用rememberMe的功能可以直接訪問
-
perm: 該資源必須得到資源權限才可以訪問
-
role: 該資源必須得到角色權限才可以訪問
這里面只用到了身份認證和授權,權限認證只用到了一點點,shiro的原理是封裝的過濾器,他能夠在訪問瀏覽器前能過自動完成一些內容。
shiro配置主要兩部分——shiroconfig和自定義的Realm(繼承AuthorizingRealm)。其中,shiroconfig是shiro的主要配置文件,而自定義的Realm主要是重寫AuthorizingRealm的兩個方法,分別是身份認證和授權認證調用數據庫查詢比對。而如果需要role訪問則需要重寫一個filter。
前奏
項目結構:
環境:
- Springboot2
- mybatis
- shiro
新建表:
對應的bean:
package com.shiro.bean;public class student {private String username;private String password;private String role;private String perm;//省略get setmybatis簡單查詢:
package com.shiro.mapper;import com.shiro.bean.student; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select;@Mapper public interface studentMapper {@Select("select * from student where username=#{name}")student findByName(String name); }省略html和sql,詳細可以到GitHub下載
頁面目錄,:
shiro核心配置文件(rolesFilter可選)。
UserRealm.java
package com.shiro.config;import com.shiro.bean.student; import com.shiro.mapper.studentMapper; 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.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired;/*** 自定義Realm* @author bigsai**/ public class UserRealm extends AuthorizingRealm{@Autowired(required = false)private studentMapper studentMapper;private final Logger logger= LoggerFactory.getLogger(UserRealm.class);/*** 執行授權邏輯*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {logger.info("執行邏輯授權");//給資源進行授權SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();//添加資源的授權字符串//到數據庫查詢當前登錄用戶的授權字符串//獲取當前登錄用戶Subject subject = SecurityUtils.getSubject();student user = (student) subject.getPrincipal();student dbUser = studentMapper.findByName(user.getUsername());info.addRole(user.getRole());//添加role 和perms role代表角色 perms代表操作,或者動作等。用于顆?;瘷嘞薰芾?/span>info.addStringPermission(dbUser.getPerm());System.out.println("user:" dbUser.getPerm());return info;}/*** 執行認證邏輯*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {System.out.println("執行認證邏輯");//編寫shiro判斷邏輯,判斷用戶名和密碼//1.判斷用戶名UsernamePasswordToken token = (UsernamePasswordToken)arg0;student user = studentMapper.findByName(token.getUsername());if(user==null){//用戶名不存在return null;//shiro底層會拋出UnKnowAccountException}//2.判斷密碼return new SimpleAuthenticationInfo(user,user.getPassword(),"");}}rolesFilter
package com.shiro.config;import org.apache.shiro.subject.Subject; import org.apache.shiro.web.filter.authz.AuthorizationFilter;import javax.servlet.ServletRequest; import javax.servlet.ServletResponse;// AuthorizationFilter抽象類事項了javax.servlet.Filter接口,它是個過濾器。 public class rolesFilter extends AuthorizationFilter {@Overrideprotected boolean isAccessAllowed(ServletRequest req, ServletResponse resp, Object mappedValue) throws Exception {Subject subject = getSubject(req, resp);String[] rolesArray = (String[]) mappedValue;if (rolesArray == null || rolesArray.length == 0) { //沒有角色限制,有權限訪問return true;}for (int i = 0; i < rolesArray.length; i ) {if (subject.hasRole(rolesArray[i])) { //若當前用戶是rolesArray中的任何一個,則有權限訪問return true;}}return false;} }shiroConfig:shiro的主要配置
package com.shiro.config;import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;import javax.servlet.Filter; import java.util.LinkedHashMap; import java.util.Map;/*** Shiro的配置類** @author bigsai*/ @Configuration public class ShiroConfig {/*** 創建ShiroFilterFactoryBean*/@Beanpublic ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();//設置安全管理器shiroFilterFactoryBean.setSecurityManager(securityManager);Map filtersMap = new LinkedHashMap<>();filtersMap.put("rolesFilter",new rolesFilter());shiroFilterFactoryBean.setFilters(filtersMap);//使用自定義fitter//添加Shiro內置過濾器/*** Shiro內置過濾器,可以實現權限相關的攔截器* 常用的過濾器:* anon: 無需認證(登錄)可以訪問* authc: 必須認證才可以訪問* user: 如果使用rememberMe的功能可以直接訪問* perm: 該資源必須得到資源權限才可以訪問* role: 該資源必須得到角色權限才可以訪問*/Map filterMap = new LinkedHashMap();filterMap.put("/login", "anon");//要將登陸的接口放出來,不然沒權限訪問登陸的接口filterMap.put("/getcontroller", "anon"); ////授權過濾器//注意:當前授權攔截后,shiro會自動跳轉到未授權頁面filterMap.put("/add", "perms[add]");filterMap.put("/update", "perms[update]");//filterMap.put("/test1.html","rolesFilter[admin,user]");filterMap.put("/*", "authc");//authc即為認證登陸后即可訪問//修改調整的登錄頁面shiroFilterFactoryBean.setLoginUrl("/index");//設置未授權提示頁面shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);return shiroFilterFactoryBean;}/*** 創建DefaultWebSecurityManager*/@Bean(name = "securityManager")public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();//關聯realmsecurityManager.setRealm(userRealm);return securityManager;}/*** 創建Realm*/@Bean(name = "userRealm")public UserRealm getRealm() {return new UserRealm();}}身份認證
身份認證,就是登錄校檢。這是第一層過濾,并且當用戶沒有登錄的時候,回退到沒登陸的界面。在controller中,login的核心為:
@RequestMapping("/login")public String login(String name, String password, Model model, HttpServletRequest request) {model.addAttribute("nama", "給個star");/*** 使用Shiro編寫認證操作*///1.獲取SubjectSubject subject = SecurityUtils.getSubject();//2.封裝用戶數據UsernamePasswordToken token = new UsernamePasswordToken(name, password);//3.執行登錄方法try {subject.login(token);//登錄成功//跳轉return "redirect:/index2";} catch (UnknownAccountException e) {//e.printStackTrace();//登錄失敗:用戶名不存在model.addAttribute("msg", "用戶名不存在");return "login";} catch (IncorrectCredentialsException e) {//e.printStackTrace();//登錄失敗:密碼錯誤model.addAttribute("msg", "密碼錯誤");return "login";}}releam中
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {System.out.println("執行認證邏輯");//編寫shiro判斷邏輯,判斷用戶名和密碼//1.判斷用戶名UsernamePasswordToken token = (UsernamePasswordToken)arg0;student user = studentMapper.findByName(token.getUsername());if(user==null){//用戶名不存在return null;//shiro底層會拋出UnKnowAccountException}//2.判斷密碼return new SimpleAuthenticationInfo(user,user.getPassword(),"");}而這只是表象的處理過程,而在releam(繼承AuthorizingRealm)中需要充血doGetAuthenticationInfo()方法.
大致流程為:登錄——>拿賬號密碼檢驗———>用著token的賬號通過你的sql查詢對象——>比對數據是否一致——>通過還是拋各種異常
而在shiroConfig中,基于url過濾時authc即可訪問
多表登錄源如何操作?
可能會遇到如下情況:教師端,學生端來自兩張表,兩個登錄接口,我該如何使用shiro身份認證。對于這種問題,你可以配置多個releam,但是我覺得如果簡單你可以在不同的登錄接口下傳遞一個參數過來,這個參數就用session傳遞。因為,shiro的session和網頁httprequest獲得的session是同一個session。
所以當你在login傳遞一個屬性到releam中,可用 if else判斷然后不同登錄接口執行不同的查詢方法即可。
授權管理
接上流程
是否登錄——>是/否——(是)—>查詢role/perm添加到subject——>過濾器校驗該url需要權限——>可以訪問/權限不足
shiro主要url可以根據角色(role)和資源(perm)的管理。對于role,可以是管理員,教師等,而perm,可能是一個動作,一個操作,等等。并且可能一個角色擁有多個role和perm。
同理,授權就是查詢數據庫的role或者perm字段添加到角色中。當然具體api不做介紹。
主要方法為上述:
而url中也是
filterMap.put("/add", "perms[add]");filterMap.put("/update", "roles[admin]");如何解決界面多角色/資源問題
常常遇到這種情況:一個接口/頁面,有兩個或者以上角色可以訪問。然后再后臺的過濾器配置總。shiro默認的配置是and而不是or。這就需要我們自己定義filter繼承AuthorizationFilter從寫對應方法。
以多角色訪問為例子。從寫上述就是文件rolesFilter。在使用的時候也要首先聲明filter才能使用。
訪問效果
在頁面授權的
運行測試:訪問其他接口都被返回到這個界面
登陸成功后,界面可以訪問
有個小注意點:如果mybatis2.0版本回和spring-start-web有沖突。我用1.3.2版本沒問題。
參考:百度百科
項目github地址
springboot一些學習整合完整地址
如果對后端、爬蟲等感性趣歡迎關注我的個人公眾號交流:bigsai
總結
以上是生活随笔為你收集整理的Springboot整合shiro基于url身份认证和授权认证的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Apache shiro介绍
- 下一篇: Springboot文件上传 百度ocr