1. 程式人生 > 實用技巧 >spingboot+shiro實現後端許可權管理

spingboot+shiro實現後端許可權管理

⭐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");
    }
}

⭐ok,這樣就結束了,shiro的Security Manager會幫你管理這一切的