Apache Shiro是一個功能強大且易於使用的Java安全框架,它爲開發人員提供了一種直觀,全面的身份驗證,受權,加密和會話管理解決方案。下面是在SpringBoot中使用Shiro進行認證和受權的例子,代碼以下:java
導入SpringBoot和Shiro依賴:web
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.2</version> </dependency> </dependencies>
也能夠直接導入Apache Shiro提供的starter:算法
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-starter</artifactId> </dependency>
package com.cf.shiro1.config; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.realm.Realm; 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 java.util.HashMap; import java.util.Map; @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //設置安全管理器 shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager); //設置未認證(登陸)時,訪問須要認證的資源時跳轉的頁面 shiroFilterFactoryBean.setLoginUrl("/loginPage"); //設置訪問無權限的資源時跳轉的頁面 shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorizedPage"); //指定路徑和過濾器的對應關係 Map<String, String> filterMap = new HashMap<>(); //設置/user/login不須要登陸就能訪問 filterMap.put("/user/login", "anon"); //設置/user/list須要登陸用戶擁有角色user時才能訪問 filterMap.put("/user/list", "roles[user]"); //其餘路徑則須要登陸才能訪問 filterMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); return shiroFilterFactoryBean; } @Bean public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("realm") Realm realm) { DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); defaultWebSecurityManager.setRealm(realm); return defaultWebSecurityManager; } @Bean public Realm realm() { MyRealm realm = new MyRealm(); //使用HashedCredentialsMatcher帶加密的匹配器來替換原先明文密碼匹配器 HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); //指定加密算法 hashedCredentialsMatcher.setHashAlgorithmName("MD5"); //指定加密次數 hashedCredentialsMatcher.setHashIterations(3); realm.setCredentialsMatcher(hashedCredentialsMatcher); return realm; } }
package com.cf.shiro1.config; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.crypto.hash.SimpleHash; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ByteSource; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; public class MyRealm extends AuthorizingRealm { /** * 受權 * * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { Object username = principalCollection.getPrimaryPrincipal(); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); simpleAuthorizationInfo.setRoles(getRoles(username.toString())); return simpleAuthorizationInfo; } /** * 認證 * * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; String username = token.getUsername(); Map<String, Object> userInfo = getUserInfo(username); if (userInfo == null) { throw new UnknownAccountException(); } //鹽值,此處使用用戶名做爲鹽 ByteSource salt = ByteSource.Util.bytes(username); SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, userInfo.get("password"), salt, getName()); return authenticationInfo; } /** * 模擬數據庫查詢,經過用戶名獲取用戶信息 * * @param username * @return */ private Map<String, Object> getUserInfo(String username) { Map<String, Object> userInfo = null; if ("zhangsan".equals(username)) { userInfo = new HashMap<>(); userInfo.put("username", "zhangsan"); //加密算法,原密碼,鹽值,加密次數 userInfo.put("password", new SimpleHash("MD5", "123456", username, 3)); } return userInfo; } /** * 模擬查詢數據庫,獲取用戶角色列表 * * @param username * @return */ private Set<String> getRoles(String username) { Set<String> roles = new HashSet<>(); roles.add("user"); roles.add("admin"); return roles; } }
package com.cf.shiro1.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.subject.Subject; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/user") public class UserController { /** * 登陸 * @param username * @param password * @return */ @RequestMapping("/login") public String userLogin(String username, String password) { String result; //獲取當前用戶 Subject currentUser = SecurityUtils.getSubject(); //用戶是否已經登陸,未登陸則進行登陸 if (!currentUser.isAuthenticated()) { //封裝用戶輸入的用戶名和密碼 UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password); try { //登陸,進行密碼比對,登陸失敗時將會拋出對應異常 currentUser.login(usernamePasswordToken); result = "登陸成功"; } catch (UnknownAccountException uae) { result = "用戶名不存在"; } catch (IncorrectCredentialsException ice) { result = "密碼錯誤"; } catch (LockedAccountException lae) { result = "用戶狀態異常"; } catch (AuthenticationException ae) { result = "登陸失敗,請與管理員聯繫"; } } else { result = "您已經登陸成功了"; } return result; } @RequestMapping("/list") public String userList() { return "訪問我須要登陸而且須要擁有user角色!"; } }