spingboot+shiro實現後端許可權管理
阿新 • • 發佈:2020-09-11
⭐shiro的結構圖
⭐shiro內部採用的是session+sessionId進行的會話管理(有狀態認證)
⭐當然你也可以整合jwt實現無狀態認證
Ok,直接乾貨!!!!
1. 第一步:加依賴
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency>
2.第二步:寫一個shiroConfig類
@Configuration public class ShiroConfig { /** * 建立shiro的一個過濾器 */ @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean() { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //設定安全管理器 shiroFilterFactoryBean.setSecurityManager(getDefaultWebSecurityManager()); /** * 新增shiro的內建過濾器:一般用兩種 anon:允許通過;authc:必須認證 * 還有就是user:如果使用rememberMe的功能就可以訪問 * perms:該資源必須得到許可權資源才可以訪問 * role:必須得到角色許可權才可以訪問 */ //必須保證順序插入所以使用LinkedHashMap Map<String, String> filterMap = new LinkedHashMap<>(); //認證過濾器 filterMap.put("自定義無需認證", "anon"); //filterMap.put("/user/*", "authc"); //授權過濾器 filterMap.put("/user/hello", "perms[自定義]");//例子:user:add //未認證的跳轉頁面(也就是未登入的使用者) shiroFilterFactoryBean.setLoginUrl("/toLogin"); //未授權訪問跳轉的頁面(也就是沒有許可權的使用者) shiroFilterFactoryBean.setUnauthorizedUrl("/error"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); return shiroFilterFactoryBean; } /** * 建立SecurityManager */ @Bean public DefaultWebSecurityManager getDefaultWebSecurityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //關聯Realm securityManager.setRealm(getRealm()); return securityManager; } /** * 建立Realm:需要自定義一個realm的類 */ @Bean public MyRealm getRealm() { MyRealm myRealm = new MyRealm(); // 配置 加密 (在加密後,不配置的話會導致登陸密碼失敗) myRealm.setCredentialsMatcher(hashedCredentialsMatcher()); return myRealm; } @Bean public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); // 使用md5 演算法進行加密 hashedCredentialsMatcher.setHashAlgorithmName("md5"); // 設定雜湊次數: 意為加密幾次 hashedCredentialsMatcher.setHashIterations(2); return hashedCredentialsMatcher; } }
3.第三步:寫一個自定義的認證授權Realm
public class MyRealm extends AuthorizingRealm { /** * 執行授權邏輯 * * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { // 獲取登入使用者資訊 Object primaryPrincipal = principalCollection.getPrimaryPrincipal(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //執行授權邏輯 info.addStringPermission("user:add"); return info; } /** * 執行認證邏輯 * * @param authenticationToken:這個就是前面subject.login()傳遞過來的token * @return 認證不通過就返回null * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //執行認證的過程 //從資料庫拿出賬號密碼和使用者傳遞過來的賬號密碼對比 UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken; String username = usernamePasswordToken.getUsername(); //資料查詢賬號密碼 if (!username.equals("資料庫賬號")) { return null;//返回為空,shiro會丟擲UnKnowAccountException(也就是賬號不存在) } //密碼不需要判斷,直接返回一個AuthenticationInfo的實現類,把資料庫密碼做引數,shiro會自己判斷的 //shiro內建的加密演算法 ByteSource credentialsSalt = ByteSource.Util.bytes("user.getUsername" + "user.getSalt()");//從資料庫查詢的 return new SimpleAuthenticationInfo(username, "資料庫加密之後的密碼", credentialsSalt, this.getName()); } }
4.第四步:寫一個登入方法吧
@RequestMapping("/user")
public class UserController {
/**
* 使用shiro進行登入認證操作
*/
@GetMapping(value = "/login")
public String login(String name, String password) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(name, password);
//傳入一個AuthenticationToken型別的token,這裡貌似UsernamePasswordToken型別的token會自動轉化為AuthenticationToken
subject.login(token);
//login會直接交給shiro的自定義的Realm的認證方法處理
//登入失敗的話就會丟擲異常,根據異常類別來判斷錯誤的型別,比如說:賬號不存在或者密碼錯誤:拋異常可以用try catch來丟擲不同異常,但是我們也可以自定義統一異常處理類,這裡就不詳述了,可以看我另一個部落格
/**
*
*/
return "登入成功";
}
@GetMapping("/hello")
public void run() {
System.out.println("hello");
}
}