個人定制網(wǎng)站軟件關(guān)鍵詞排名
第一章 入門概述
1.概念
shiro是一個Java安全框架,可以完成:認證、授權(quán)、加密、會話管理、與web集成、緩存…
2.優(yōu)勢
● 易于使用,構(gòu)建簡單
● 功能全面
● 靈活,可以在任何應(yīng)用程序環(huán)境中工作,并且不需要依賴它們
● 高效支持web,可以基于應(yīng)用程序URL和Web協(xié)議創(chuàng)建靈活的安全策略
● 兼容性強,易于和其他框架和應(yīng)用程序集成
● 社區(qū)支持
3.與springsecurity的區(qū)別
● shiro需要和spring整合開發(fā),而springsecurity基于spring開發(fā),配合起來更便利
● springsecurity比shiro功能豐富,如安全維護
● shiro配置和使用簡單,springsecurity較難
● shiro依賴性低,不需要任何框架和容器,可以獨立運行,而springsecurity需要依賴spring容器
● shiro可以工作于任何應(yīng)用環(huán)境,獨立于容器
4.基本功能
- Authentication:身份認證/登錄,驗證用戶是否擁有對應(yīng)的身份
- authorization:權(quán)限驗證,驗證用戶是否擁有某個權(quán)限,判斷用戶可以進行什么操作
- session management:會話管理,即用戶登錄后的一次會話,在沒有登出之前,所有的信息都保存在會話中
- cryptography:加密,保證數(shù)據(jù)的安全,比如密碼加密存儲數(shù)據(jù)庫
- web support:web支持,集成web環(huán)境
- caching:緩存,比如用戶登錄后,用戶信息、角色和權(quán)限保存下來
- concurrency:多線程并發(fā)驗證,比如在一個線程紅開啟另一個線程,可以把權(quán)限自動傳播過去
- Testing:測試功能
- run as:偽裝用戶
- remember me:記住我
5.原理
shiro外部架構(gòu)
subject:對外API核心,與應(yīng)用代碼直接交互的對象,與subject的所有交互都會委托為securitymanager
securitymanager:安全管理器,所有與安全相關(guān)的操作都會與securitymanager交互,管理所有的subject,是shiro的核心,相當于spingmvc的dispatcherservlet的角色
realm:從realm中獲取安全數(shù)據(jù)信息(用戶、角色、權(quán)限)
shiro內(nèi)部架構(gòu)
- Subject:任何可以與應(yīng)用交互的“用戶”
- SecurityManager :相當于 SpringMVC 中的 DispatcherServlet;是 Shiro 的心臟; 所有具體的交互都通過 SecurityManager 進行控制;它管理著所有 Subject、且負責進 行認證、授權(quán)、會話及緩存的管理
- Authenticator:負責 Subject 認證,是一個擴展點,可以自定義實現(xiàn);可以使用認證策略(Authentication Strategy),即什么情況下算用戶認證通過了
- Authorizer:授權(quán)器、即訪問控制器,用來決定主體是否有權(quán)限進行相應(yīng)的操作;即控制著用戶能訪問應(yīng)用中的哪些功能
- Realm:可以有 1 個或多個 Realm,可以認為是安全實體數(shù)據(jù)源,即用于獲取安全實體的;可以是 JDBC 實現(xiàn),也可以是內(nèi)存實現(xiàn)等等;由用戶提供;所以一般在應(yīng)用中都需要實現(xiàn)自己的 Realm
- SessionManager:管理 Session 生命周期的組件
- CacheManager:緩存控制器,來管理如用戶、角色、權(quán)限等的緩存的;因為這些數(shù)據(jù) 基本上很少改變,放到緩存中后可以提高訪問的性能
- Cryptography:密碼模塊,Shiro 提高了一些常見的加密組件用于如密碼加密/解密。
第二章 基本使用
1.環(huán)境搭建
● 引入依賴
<dependencies><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.9.0</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency>
</dependencies>
● ini文件:src/main/resources/shiro.ini
[users]
zhangsan=z3
lisi=l4
2.登錄認證
概念:
① 身份驗證:一般需要提供如身份ID等一些標識信息來表明登錄者的身份,如提供email,用戶名/密碼來證明
② 在shiro中,用戶需要提供principals(身份)和credentials(證明)給shiro,從而應(yīng)用能驗證用戶身份
③ principals:身份,即主體的標識屬性,可以是任何屬性,如用戶名、郵箱等,唯一即可。一個主體可以有多個principals,但只有一個Primary principals,一般是用戶名/郵箱/手機號
④ credentials:證明/憑證,即只有主體知道的安全值,如密碼/數(shù)字證書等
最常見的principals和credentials組合就是用戶名/密碼
流程:
① 收集用戶身份/憑證,即如用戶名/密碼
② 調(diào)用 Subject.login 進行登錄,如果失敗將得到相應(yīng) 的 AuthenticationException異常,根據(jù)異常提示用戶 錯誤信息;否則登錄成功
③ 創(chuàng)建自定義的 Realm 類,繼承 org.apache.shiro.realm.AuthenticatingRealm類,實現(xiàn) doGetAuthenticationInfo() 方法
實例:
public class ShiroRun {public static void main(String[] args) {//1.初始化獲取securitymanagerIniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");SecurityManager securityManager = factory.getInstance();SecurityUtils.setSecurityManager(securityManager);//2.獲取subject對象Subject subject = SecurityUtils.getSubject();//3.創(chuàng)建token對象,web應(yīng)用用戶名密碼從頁面?zhèn)鬟fAuthenticationToken token = new UsernamePasswordToken("zhangsan", "z3");//4.完成登錄try {subject.login(token);System.out.println("login successful");} catch (UnknownAccountException e) {e.printStackTrace();System.out.println("用戶不存在");}catch (IncorrectCredentialsException e) {e.printStackTrace();System.out.println("密碼錯誤");}catch (AuthenticationException e) {e.printStackTrace();System.out.println("登錄失敗");}}
}
3.授權(quán)
① 授權(quán),也叫訪問控制,即在應(yīng)用中控制誰訪問哪些資源(如訪問頁面/編輯數(shù)據(jù)/頁面 操作等)。在授權(quán)中需了解的幾個關(guān)鍵對象:主體(Subject)、資源(Resource)、權(quán)限 (Permission)、角色(Role)
② 主體(Subject):訪問應(yīng)用的用戶,在 Shiro 中使用 Subject 代表該用戶。用戶只有授權(quán) 后才允許訪問相應(yīng)的資源
③ 資源(Resource):在應(yīng)用中用戶可以訪問的 URL,比如訪問 JSP 頁面、查看/編輯 某些 數(shù)據(jù)、訪問某個業(yè)務(wù)方法、打印文本等等都是資源。用戶只要授權(quán)后才能訪問
④ 權(quán)限(Permission):安全策略中的原子授權(quán)單位,通過權(quán)限我們可以表示在應(yīng)用中用戶 有沒有操作某個資源的權(quán)力。即權(quán)限表示在應(yīng)用中用戶能不能訪問某個資源,如:訪問用 戶列表頁面查看/新增/修改/刪除用戶數(shù)據(jù)(即很多時候都是CRUD(增查改刪)式權(quán)限控 制)等。權(quán)限代表了用戶有沒有操作某個資源的權(quán)利,即反映在某個資源上的操作允不允許
⑤ Shiro 支持粗粒度權(quán)限(如用戶模塊的所有權(quán)限)和細粒度權(quán)限(操作某個用戶的權(quán)限, 即實例級別的)
⑥ 角色(Role):權(quán)限的集合,一般情況下會賦予用戶角色而不是權(quán)限,即這樣用戶可以擁有 一組權(quán)限,賦予權(quán)限時比較方便。典型的如:項目經(jīng)理、技術(shù)總監(jiān)、CTO、開發(fā)工程師等都是角色,不同的角色擁有一組不同的權(quán)限
授權(quán)方式:
- 編程式:
subject.hasRole("admin")
- 注解式:
@RequiresRoles("admin")
- jsp/gsp標簽:
<shiro:hasRole name="admin"></shiro:hasRole>
授權(quán)流程:
- 首先調(diào)用Subject.isPermitted*/hasRole*接口,其會委托給SecurityManager,而SecurityManager接著會委托給 Authorizer
- Authorizer是真正的授權(quán)者,如果調(diào)用如isPermitted(“user:view”),其首先會通過PermissionResolver把字符串轉(zhuǎn)換成相應(yīng)的Permission實例
- 在進行授權(quán)之前,其會調(diào)用相應(yīng)的Realm獲取Subject相應(yīng)的角色/權(quán)限用于匹配傳入的角色/權(quán)限
- Authorizer會判斷Realm的角色/權(quán)限是否和傳入的匹配,如果有多個Realm,會委托給ModularRealmAuthorizer進行循環(huán)判斷,如果匹配如isPermitted*/hasRole* 會返回 true,否則返回false表示授權(quán)失敗
實例:
1.給shiro.ini增加角色配置
[users]
fate=admin,role1,role2
fuck=123456
2.增加權(quán)限配置
[roles]
role1=user:insert,user:select
3.測試代碼
public static void main(String[] args) {//1.初始化獲取securitymanagerIniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");SecurityManager securityManager = factory.getInstance();SecurityUtils.setSecurityManager(securityManager);//2.獲取subject對象Subject subject = SecurityUtils.getSubject();//3.創(chuàng)建token對象,web應(yīng)用用戶名密碼從頁面?zhèn)鬟fAuthenticationToken token = new UsernamePasswordToken("zhangsan", "z3");//4.完成登錄try {subject.login(token);System.out.println("login successful");//5.判斷角色boolean hasRole = subject.hasRole("role1");System.out.println("是否擁有role1角色:" + hasRole);//6.判斷權(quán)限boolean permitted = subject.isPermitted("user:insert");System.out.println("是否擁有此權(quán)限:" + permitted);//也可以用checkPermission方法,但沒有返回值,沒權(quán)限拋AuthenticationExceptionsubject.checkPermission("user:update");} catch (UnknownAccountException e) {e.printStackTrace();System.out.println("用戶不存在");} catch (IncorrectCredentialsException e) {e.printStackTrace();System.out.println("密碼錯誤");} catch (AuthenticationException e) {e.printStackTrace();System.out.println("登錄失敗");}
}
4.加密
Shiro內(nèi)嵌很多常用的加密算法,比如MD5加密
public class ShiroMD5 {public static void main(String[] args) {//密碼明文String password = "admin";//使用MD5加密Md5Hash md5Hash = new Md5Hash(password);System.out.println("md5加密:" + md5Hash);//帶鹽的md5加密,鹽就是在密碼明文后拼接新字符串,然后再進行加密Md5Hash md5Hash1 = new Md5Hash(password, "salt");System.out.println("帶鹽的md5加密:" + md5Hash1.toHex());//為了保證安全,避免被破解還可以多次迭代加密,保證數(shù)據(jù)安全Md5Hash md5Hash2 = new Md5Hash(password, "salt", 3);System.out.println("帶鹽的3次迭代加密:" + md5Hash2);//使用父類進行加密SimpleHash simpleHash = new SimpleHash("MD5", password, "salt", 3);System.out.println("父類帶鹽的3次加密:" + simpleHash);}
}
5.自定義登錄認證
Shiro 默認的登錄認證是不帶加密的,如果想要實現(xiàn)加密認證需要自定義登錄認證, 自定義Realm
public class MyRealm extends AuthenticatingRealm {//自定義登錄認證方法,shiro的login方法的底層會調(diào)用該類的認證方法進行認證//需要配置自定義的realm生效,應(yīng)該在ini文件中配置,如果有springboot框架,也可以在Springboot中進行配置//該方法只是獲取進行對比的信息,認證邏輯還是按照shiro的底層認證邏輯來完成protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {//1.獲取身份信息String principal = authenticationToken.getPrincipal().toString();//2.獲取憑證信息String password = new String((char[]) authenticationToken.getCredentials());System.out.println("認證的用戶信息:" + principal + "---" + password);//3.獲取數(shù)據(jù)庫中存儲的用戶信息if(principal.equals("zhangsan")){//3.1數(shù)據(jù)庫中存儲的加鹽3次迭代的密碼String pwdInfo = "b073e9301c412431159e7075340c4c66";//4.創(chuàng)建封裝校驗邏輯的對象,封裝數(shù)據(jù)返回AuthenticationInfo info = new SimpleAuthenticationInfo(authenticationToken.getPrincipal(),pwdInfo,ByteSource.Util.bytes("salt"),authenticationToken.getPrincipal().toString());return info;}return null;}
}
添加配置信息,讓shiro知曉你使用的是自定義的Realm
[main]
#在shiro.ini中添加配置信息
md5CredentialsMatcher=org.apache.shiro.authc.credential.Md5CredentialsMatcher
md5CredentialsMatcher.hashIterations=3
myrealm=com.atguigu.shirotest.MyRealm
myrealm.credentialsMatcher=$md5CredentialsMatcher
securityManager.realms=$myrealm[users]
zhangsan=7174f64b13022acd3c56e2781e098a5f,role1,role2
lisi=l4 [roles]
role1=user:insert,user:select
第三章 與springboot整合
框架整合
1.引入依賴:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.1.RELEASE</version>
</parent>
<dependencies><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-web-starter</artifactId><version>1.9.0</version></dependency><!--mybatis-plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.0.5</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.46</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
</dependencies>
2.配置文件
# mybatis配置
mybatis-plus:configuration:# 日志log-impl: org.apache.ibatis.logging.stdout.StdOutImplmapper-locations: classpath:mapper/ *.xmlspring:
# 數(shù)據(jù)庫配置datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/shirodb?characterEncoding=utf-8&useSSL=falsepassword: rootusername: root
# json格式j(luò)ackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: GMT+8shiro:
# 登錄接口loginUrl: /myController/login
3.自定義realm
@Component
public class MyRealm extends AuthorizingRealm{@Autowiredprivate UserService userService;//自定義授權(quán)方法@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}//自定義登錄認證方法@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {//1.獲取用戶身份信息String name = authenticationToken.getPrincipal().toString();//2.調(diào)用業(yè)務(wù)層獲取用戶信息(數(shù)據(jù)庫)User user = userService.getUserInfoByName(name);//3.非空判斷,將數(shù)據(jù)封裝返回if(user != null){AuthenticationInfo info = new SimpleAuthenticationInfo(authenticationToken.getPrincipal(),user.getPwd(),ByteSource.Util.bytes("salt"),authenticationToken.getPrincipal().toString());return info;}return null;}
}
4.配置類
@Slf4j
@Configuration
public class ShiroConfig {@Autowiredprivate MyRealm myRealm;//配置SecurityManager@Beanpublic DefaultWebSecurityManager defaultWebSecurityManager(){//1.創(chuàng)建defaultWebSecurityManager 對象DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();//2.創(chuàng)建加密對象,設(shè)置相關(guān)屬性HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();//2.1 采用md5加密matcher.setHashAlgorithmName("md5");//2.2 迭代加密次數(shù)matcher.setHashIterations(3);//3.將加密對象存儲到myRealm中myRealm.setCredentialsMatcher(matcher);//4.將myRealm存入defaultWebSecurityManager 對象defaultWebSecurityManager.setRealm(myRealm);//5.返回return defaultWebSecurityManager;}//配置Shiro內(nèi)置過濾器攔截范圍@Beanpublic DefaultShiroFilterChainDefinition shiroFilterChainDefinition(){DefaultShiroFilterChainDefinition defaultShiroFilterChainDefinition = new DefaultShiroFilterChainDefinition();
// 設(shè)置不認證就可以訪問的資源defaultShiroFilterChainDefinition.addPathDefinition("/myController/userLogin","anon");defaultShiroFilterChainDefinition.addPathDefinition("/login","anon");
// 設(shè)置需要進行登錄認證的攔截范圍defaultShiroFilterChainDefinition.addPathDefinition("/**","authc");return defaultShiroFilterChainDefinition;}
}
5.編寫控制類
@Controller
@RequestMapping("myController")
public class MyController{@GetMapping("userLogin")@ResponseBobypublic String userLogin(String name,String pwd){//1.獲取subject對象Subject subject = SecurityUtils.getSubject();//2.封裝請求數(shù)據(jù)到tokenAuthenticationToken token = new UsernamePasswordToken(name,pwd);//3.調(diào)用login方法進行登錄認證try{ subject.login(token);return "登錄成功";}catch(AuthenticationException e){e.printStackTrace();System.out.println("登錄失敗");return "登錄失敗";}
}