SpringBoot整合Shiro (二)
阿新 • • 發佈:2018-08-15
mark alc depend sco repo 服務 框架 filter des
Apache Shiro是一個強大且易用的Java安全框架,執行身份驗證、授權、密碼學和會話管理。相比較Spring Security,shiro有小巧、簡單、易上手等的優點。所以很多框架都在使用shiro。
Shiro包含了三個核心組件:Subject, SecurityManager 和 Realms。
- Subject 代表了當前用戶的安全操作。
- SecurityManager 則管理所有用戶的安全操作。它是Shiro框架的核心,典型的Facade模式,Shiro通過SecurityManager來管理內部組件實例,並通過它來提供安全管理的各種服務。
- Realm 充當了Shiro與應用安全數據間的“橋梁”或者“連接器”。也就是說,當對用戶執行認證(登錄)和授權(訪問控制)驗證時,Shiro會從應用配置的Realm中查找用戶及其權限信息。
下面通過示例來演示SpringBoot如何來整合Shiro
1、創建項目ShiroDemo
2、配置POM,添加SpringBoot以及Shiro依賴
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.25</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>0.2.23</version> </dependency> <!-- shiro權限控制框架 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency> </dependencies>
3、編寫MyShiroRealm類,實現AuthorizingRealm接口
public class MyShiroRealm extends AuthorizingRealm { /** * 授權用戶權限 */ @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { //獲取用戶 User user = (User)SecurityUtils.getSubject().getPrincipal(); SimpleAuthorizationInfo info= new SimpleAuthorizationInfo(); //獲取用戶角色 Set<String> roleSet = new HashSet<String>(); roleSet.add("100002"); info.setRoles(roleSet); //獲取用戶權限 Set<String> permissionSet = new HashSet<String>(); permissionSet.add("權限添加"); permissionSet.add("權限刪除"); info.setStringPermissions(permissionSet); return info; } /** * 驗證用戶身份 */ @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken authcToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; String username = token.getUsername(); String password = String.valueOf(token.getPassword()); Map<String, Object> map = new HashMap<String, Object>(); map.put("nickname", username); //密碼進行加密處理 明文為 password+name String paw = password+username; String pawDES = MyDES.encryptBasedDes(paw); map.put("pswd", pawDES); User user = new User(); user.setId("112222"); user.setUsername(username); user.setPassword(pawDES); return new SimpleAuthenticationInfo(user, password, getName()); } }
4、實現ShiroConfiguration
@Configuration public class ShiroConfiguration { /** * ShiroFilterFactoryBean 處理攔截資源文件問題。 * 註意:單獨一個ShiroFilterFactoryBean配置是或報錯的,以為在 * 初始化ShiroFilterFactoryBean的時候需要註入:SecurityManager * * Filter Chain定義說明 1、一個URL可以配置多個Filter,使用逗號分隔 2、當設置多個過濾器時,全部驗證通過,才視為通過 * 3、部分過濾器可指定參數,如perms,roles * */ @Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必須設置 SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager); // 如果不設置默認會自動尋找Web工程根目錄下的"/login.jsp"頁面 shiroFilterFactoryBean.setLoginUrl("/login"); // 登錄成功後要跳轉的鏈接 shiroFilterFactoryBean.setSuccessUrl("/index"); // 未授權界面; shiroFilterFactoryBean.setUnauthorizedUrl("/403"); //自定義攔截器 Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>(); //限制同一帳號同時在線的個數。 //filtersMap.put("kickout", kickoutSessionControlFilter()); shiroFilterFactoryBean.setFilters(filtersMap); // 權限控制map. Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); // 配置不會被攔截的鏈接 順序判斷 // 配置退出過濾器,其中的具體的退出代碼Shiro已經替我們實現了 // 從數據庫獲取動態的權限 // filterChainDefinitionMap.put("/add", "perms[權限添加]"); // <!-- 過濾鏈定義,從上向下順序執行,一般將 /**放在最為下邊 -->:這是一個坑呢,一不小心代碼就不好使了; // <!-- authc:所有url都必須認證通過才可以訪問; anon:所有url都都可以匿名訪問--> //logout這個攔截器是shiro已經實現好了的。 // 從數據庫獲取 /*List<SysPermissionInit> list = sysPermissionInitService.selectAll(); for (SysPermissionInit sysPermissionInit : list) { filterChainDefinitionMap.put(sysPermissionInit.getUrl(), sysPermissionInit.getPermissionInit()); }*/ shiroFilterFactoryBean .setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 設置realm. securityManager.setRealm(myShiroRealm()); // 自定義緩存實現 使用redis //securityManager.setCacheManager(cacheManager()); // 自定義session管理 使用redis //securityManager.setSessionManager(sessionManager()); //註入記住我管理器; securityManager.setRememberMeManager(rememberMeManager()); return securityManager; } public MyShiroRealm myShiroRealm(){ return new MyShiroRealm(); } /** * cookie對象; * @return */ public SimpleCookie rememberMeCookie(){ //這個參數是cookie的名稱,對應前端的checkbox的name = rememberMe SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); //<!-- 記住我cookie生效時間30天 ,單位秒;--> simpleCookie.setMaxAge(2592000); return simpleCookie; } /** * cookie管理對象;記住我功能 * @return */ public CookieRememberMeManager rememberMeManager(){ CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); //rememberMe cookie加密的密鑰 建議每個項目都不一樣 默認AES算法 密鑰長度(128 256 512 位) cookieRememberMeManager.setCipherKey(Base64.decode("3AvVhmFLUs0KTA3Kprsdag==")); return cookieRememberMeManager; } }
5、編寫LoginController類測試Shiro
@RestController public class LoginController { @RequestMapping(value="/login",method=RequestMethod.POST) public String login(String username, String password,String vcode,Boolean rememberMe){ System.out.println(username); UsernamePasswordToken token = new UsernamePasswordToken(username, password,rememberMe); SecurityUtils.getSubject().login(token); return "loginSuccess"; } @RequestMapping(value="/index",method=RequestMethod.GET) public String home(){ Subject subject = SecurityUtils.getSubject(); User principal = (User)subject.getPrincipal(); return "Home"; } }
- 在postman中訪問http://127.0.0.1:8080/login,Body中攜帶參數以及值
- 訪問http://127.0.0.1:8080/index,從Subject中獲取登錄後的用戶信息
SpringBoot整合Shiro (二)