shrio&springboot&layui 前后端分離思路,及實現核心業務邏輯


總結:上期我們說到表設計,這次來實現。

            前后端分離思路:登入返回 token 根據token 獲取菜單數據,動態渲染 路由。重新shiro 的處理邏輯就行,如沒有權限,未認證 登 返貨json 格式。(前端控制 路由跳轉,后端負責數據)

            不分離 就常規套路,登入后 獲取菜單信息 渲染頁面,未認證直接跳轉 登入頁,或者沒有權限頁面,也可以通過標簽 直接看不到,反正就是簡單的很。(后端負責所有頁面跳轉和數據扭轉)。

           核心代碼如下:

          

public class CustomRealm extends AuthorizingRealm {

    @Autowired
    private SysUsersService sysUsersService;

    @Autowired
    private SysUsersMapper usersMapper;


    /**
     * 授權
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        if (principals == null) {
            throw new AuthorizationException("請重新登入");
        }
        // principals 就是 認證 傳的 第一個 參數 傳什么 強轉什么
        SysUsers user = (SysUsers) getAvailablePrincipal(principals);

        List<SysPermissions> list = usersMapper.getPermissions(user.getId());
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        Set<String> permissions = list.stream().map(e->e.getPermission()).collect(Collectors.toSet());
        info.setStringPermissions(permissions);
        return info;
    }

    /**
     * 認證
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        UsernamePasswordToken fromToken = (UsernamePasswordToken) token;
        String username = fromToken.getUsername();

        QueryWrapper<SysUsers> queryWrapper = new QueryWrapper();
        List<SysUsers> usersList = sysUsersService.list(queryWrapper);
        if(CollectionUtils.isEmpty(usersList)){
            throw new UnknownAccountException("用戶不存在");
        }
        SysUsers user = usersList.get(0);
        // 一般重次 登入 3次 密碼錯誤 就鎖定 需要重下 shiro 登入失敗 邏輯
        if(user.getLocked()>0){
            throw new LockedAccountException("賬戶被鎖定,請聯系管理員");
        }
        //從數據 查詢 根據用戶username 用戶 然后 交給 shiro 去匹配 密碼 用戶名 相等
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
       /* if (user.getSalt() != null) {
            info.setCredentialsSalt(ByteSource.Util.bytes(user.getSalt()));
        }*/

        return info;

    }

}

  核心配置如下:

      

@Configuration
public class ShiroConfig {

    /**
     *  注入自定義的realm,告訴shiro如何獲取用戶信息來做登錄或權限控制
     */

    @Bean
    public Realm realm() {
        return new CustomRealm();
    }


    /**
     * 這里統一做鑒權,即判斷哪些請求路徑需要用戶登錄,哪些請求路徑不需要用戶登錄。
     * 這里只做鑒權,不做權限控制,因為權限用注解來做。
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);
        Map<String, String> chainDefinition = new LinkedHashMap<>();
        chainDefinition.put("/user/index", "anon");
        chainDefinition.put("/user/login", "anon");
        chainDefinition.put("/static/**", "anon");
        chainDefinition.put("/css/**", "anon");
        chainDefinition.put("/js/**", "anon");
        chainDefinition.put("/swagger-ui.html", "anon");
        chainDefinition.put("/doc.html", "anon");
        chainDefinition.put("/swagger-resources", "anon");
        chainDefinition.put("/swagger-resources/configuration/security", "anon");
        chainDefinition.put("/swagger-resources/configuration/ui", "anon");
        chainDefinition.put("/v2/api-docs", "anon");
        chainDefinition.put("/webjars/springfox-swagger-ui/**", "anon");



        // 1、創建過濾器Map,用來裝自定義過濾器
        LinkedHashMap<String, Filter> map = new LinkedHashMap<>();
        // 2、將自定義過濾器放入map中,如果實現了自定義授權過濾器,那就必須在這里注冊,否則Shiro不會使用自定義的授權過濾器
        map.put("authc", new MyFormAuthenticationFilter());
        // 3、將過濾器Ma綁定到shiroFilterFactoryBean上
        factoryBean.setFilters(map);

        //設置 未認證跳轉 當然重寫 過濾器 也可以
        factoryBean.setLoginUrl("/user/unauth");
        //設置 未授權跳轉
        factoryBean.setUnauthorizedUrl("/user/unperms");

        //除了以上的請求外,其它請求都需要登錄
        chainDefinition.put("/**", "authc");
       // chainDefinition.put("/**", "anon");
        factoryBean.setFilterChainDefinitionMap(chainDefinition);
        return factoryBean;
    }

    @Bean
    public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        /**
         * setUsePrefix(false)用於解決一個奇怪的bug。在引入spring aop的情況下。
         * 在@Controller注解的類的方法中加入@RequiresRole注解,會導致該方法無法映射請求,導致返回404。
         * 加入這項配置能解決這個bug
         */
        creator.setProxyTargetClass(true);
        creator.setUsePrefix(true);
        return creator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor
                = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }


    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        //securityManager.setRealms(Arrays.asList(realm()));
        securityManager.setRealm(realm());
        // securityManager.setCacheManager(cacheManager());
        // 設置realm. 可以設置 多ream 和 策略
        //securityManager.setAuthenticator(authenticator());
        return securityManager;
    }

     /*  //添加realm
    @Bean
    public Authenticator authenticator() {
        ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
        //設置兩個Realm,一個用於用戶登錄驗證和訪問權限獲取;一個用於jwt token的認證
        authenticator.setRealms(Arrays.asList(jwtRealm()));
        //設置多個realm認證策略,一個成功即跳過其它的
        authenticator.setAuthenticationStrategy(new FirstSuccessfulStrategy());
        return authenticator;
    }*/
    /**
     * 使用默認session
     *
     * @return
     */
    @Bean(name="sessionManager")
    public ServletContainerSessionManager servletContainerSessionManager() {
        ServletContainerSessionManager sessionManager = new ServletContainerSessionManager();
        return sessionManager;
    }

  /*  *//**
     *  憑證匹配器
     * @return
     *//*
    @Bean(name = "hashedCredentialsMatcher")
    public HashedCredentialsMatcher getHashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher =  new HashedCredentialsMatcher("SHA-256");
        hashedCredentialsMatcher.setHashIterations(2);
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        return hashedCredentialsMatcher;
    }*/

}

  效果如下:

 

 接口文檔如下:

 

 

就是折磨簡單 雖然沒啥難度,但是今天還是搞了半天。

代碼結構:

源碼地址 有興趣的可以看看

https://github.com/lyc88/shiro


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM