javascript
Spring Boot + Shiro 集成
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
Spring Boot + Shiro 集成
Shiro 是一個(gè)流行的 Java 安全框架。
其實(shí) Spring 有一個(gè) Spring Security 的安全框架,我試用了一下,太復(fù)雜了。同樣的安全需求,用 Shiro 要簡單、快捷得多,也利于理解。
本手冊的源碼托管在 GitHub 上:
YorkeCao/shiro-spring-boot-sample
下面主要介紹在 Spring Boot 項(xiàng)目中引入 Shiro,對應(yīng)用進(jìn)行安全管控。
集成
可以利用 Shiro 啟動(dòng)器來完成與 Spring Boot 的集成。
這里為了簡單,盡量少做配置。實(shí)際上 Shiro 有很多自定義選項(xiàng)。詳細(xì)介紹請移步官網(wǎng)。
引入 Shiro 啟動(dòng)器
Shiro 官方提供了 Spring Boot 啟動(dòng)器:shiro-spring-boot-starter,在 pom.xml 文件中引入:
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring-boot-starter --> <dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-starter</artifactId><version>1.4.0</version> </dependency>?
配置 Shiro
這里我們提供一個(gè)最簡單的 Java Class 配置。
里面用到了一個(gè)自定義的 Realm:CustomRealm。
package io.yorkecao.sample.config;import io.yorkecao.sample.shiro.CustomRealm; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;/*** @author Yorke*/ @Configuration public class ShiroConfig {@Bean(name = "customRealm")public CustomRealm customRealm() {return new CustomRealm();}@Bean(name = "securityManager")public DefaultWebSecurityManager defaultWebSecurityManager(CustomRealm customRealm) {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager ();securityManager.setRealm(customRealm);return securityManager;}@Bean(name = "lifecycleBeanPostProcessor")public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}@Bean(name = "shiroFilter")public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();shiroFilterFactoryBean.setSecurityManager(securityManager);return shiroFilterFactoryBean;} }?
實(shí)現(xiàn)自定義 Realm
Realm 是控制認(rèn)證和授權(quán)的核心部分,也是開發(fā)人員必須自己實(shí)現(xiàn)的部分。
實(shí)現(xiàn)自定義 Realm 最快捷的方式是繼承 AuthorizingRealm 類。
package io.yorkecao.sample.shiro;import io.yorkecao.sample.dao.ShiroSampleDao; 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.springframework.beans.factory.annotation.Autowired;import java.util.Set;/*** @author Yorke*/ public class CustomRealm extends AuthorizingRealm {@Autowiredprivate ShiroSampleDao shiroSampleDao;/*** 認(rèn)證*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;String username = token.getUsername();String password = this.shiroSampleDao.getPasswordByUsername(username);return new SimpleAuthenticationInfo(username, password, getName());}/*** 授權(quán)*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {String username = (String) super.getAvailablePrincipal(principalCollection);SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();Set<String> roles = shiroSampleDao.getRolesByUsername(username);authorizationInfo.setRoles(roles);roles.forEach(role -> {Set<String> permissions = this.shiroSampleDao.getPermissionsByRole(role);authorizationInfo.addStringPermissions(permissions);});return authorizationInfo;} }這里用到了一個(gè) DAO:shiroSampleDao。應(yīng)該要通過它來從我們的數(shù)據(jù)庫中獲取用戶、角色等信息。但是為了方便,我只是模擬了一下。
package io.yorkecao.sample.dao;import org.springframework.stereotype.Repository;import java.util.*;/*** @author Yorke*/ @Repository public class ShiroSampleDao {public Set<String> getRolesByUsername(String username) {Set<String> roles = new HashSet<>();switch (username) {case "zhangsan":roles.add("admin");break;case "lisi":roles.add("guest");break;}return roles;}public Set<String> getPermissionsByRole(String role) {Set<String> permissions = new HashSet<>();switch (role) {case "admin":permissions.add("read");permissions.add("write");break;case "guest":permissions.add("read");break;}return permissions;}public String getPasswordByUsername(String username) {switch (username) {case "zhangsan":return "zhangsan";case "lisi":return "lisi";}return null;} }?
實(shí)現(xiàn) login、logout 接口
在 Shiro 框架中實(shí)現(xiàn)登錄、登出很容易。
這里我也提供了一個(gè) read 和 write 的接口,這兩個(gè)接口在 Service 實(shí)現(xiàn)。
package io.yorkecao.sample.web;import io.yorkecao.sample.service.ShiroSampleService; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;/*** @author Yorke*/ @RestController public class ShiroSampleController {@Autowiredprivate ShiroSampleService shiroSampleService;@GetMapping("/login")public void login(String username, String password) {UsernamePasswordToken token = new UsernamePasswordToken(username, password);token.setRememberMe(true);Subject currentUser = SecurityUtils.getSubject();currentUser.login(token);}@GetMapping("/logout")public void logout() {Subject currentUser = SecurityUtils.getSubject();currentUser.logout();}@GetMapping("/read")public String read() {return this.shiroSampleService.read();}@GetMapping("/write")public String write() {return this.shiroSampleService.write();} }?
通過注解設(shè)置訪問資源所需權(quán)限
可以通過 @RequiresPermissions 等注解設(shè)置訪問資源所需的權(quán)限。
package io.yorkecao.sample.service;import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.stereotype.Service;/*** @author Yorke*/ @Service public class ShiroSampleService {@RequiresPermissions("read")public String read() {return "reading...";}@RequiresPermissions("write")public String write() {return "writting...";} }?
測試
- 在登錄之前,訪問 /read 和 /write 接口都無效
- 用 lisi 登錄(GET http://localhost:8080/login?username=lisi&password=lisi)后,可以訪問 /read,不能訪問 /write
- 用 zhangsan 登錄(GET http://localhost:8080/login?username=zhangsan&password=zhangsan)后,/read 和 /write 都可以訪問
- 登出后,訪問 /read 和 /write 接口都無效
轉(zhuǎn)載于:https://my.oschina.net/YorkeCao/blog/1058017
總結(jié)
以上是生活随笔為你收集整理的Spring Boot + Shiro 集成的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 高分辨率食道测压(HRM)
- 下一篇: jQuery(三) javascript