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