摘要:簡介為一個基于框架的微服務方案以下簡稱其余略文檔簡介簡介首先關于以及等介紹以及微服務的概念在此略過本文中介紹的方法基于框架但實現思路和核心類應該可以在其他框架中通用一首先闡述一下研究這個東西的出發點一開始在中也是使用的配置文件完成對的配置的
Nutzboot簡介:
?NutzBoot為一個基于Nutz框架的微服務方案,以下簡稱NB!其余略...
?NB文檔簡介:http://www.nutzam.com/core/bo...
簡介:
?首先關于Nutz以及NB,shiro等介紹以及微服務的概念在此略過,本文中介紹的方法基于Nutz框架,但實現思路和核心類應該可以在其他框架中通用.
一.首先闡述一下研究這個東西的出發點.?一開始在NB中也是使用的shiro.ini配置文件完成對shiro的配置的,但是在實際開發過程中發現,在配置微服務的過程中,shiro文件需要配置或復制多次,這里插一嘴我們的實現方式,我們服務的實現方式為,所有需要獨立部署的服務器都會實現同一個基礎服務器運行庫,來完成通用配置等.
?在配置多個服務器的時候發現不同服務器之間如果只使用一個shiro.ini配置文件會出現,[urls]配置下的url重復的情況,即例如前后臺的/user/login接口,既是在NB的配置中配置不同服務器上下文,也無法避免同一個shiro配置文件出現此問題
?為了解決這個問題其實也想過將不同服務的配置文件分離(當然這在NB結構中是可以實現的),但是出現shiro.ini中[main]等配置被復制多次的情況,不美觀也不利于修改.
二.解決思路?為了解決這個問題其實一開始想到的是通過NB中shiro-stater中已有的 shiro.ini.urls 配置解決(這個配置允許在其他一個文件中手寫shiro urls 配置列表)
?后來發現這個配置無法和 shiro.ini配置文件一起使用(這個配置大概是給使用默認配置的同學使用的)
?而已有的shiro大部分配置都在shiro.ini配置文件中,不太可能寫成代碼形式,只能另尋他法
?最后經過幾經尋找,最終確定能解決這個問題的方法是(也修改了很多次,這里說了最后兩種)
?1.復制shiro-starter源碼,利用其中已有的重寫shiro的 EnvironmentLoaderListener的類,以和之前部分相同的邏輯初始化Shiro.
?2.修改上述Listener在傳入Environment處做修改(此處省略了starter獲取配置文件路徑并傳入的部分,以及配置非空部分),傳入一個重寫的Environment,這個重寫的類中大部分實現邏輯是由 shiro處理源碼IniWebEnvironment類復制過來的,用來完成 shiro.ini文件的配置加載.
?3.修改重寫類代碼,使其可以獲取到NB starter的配置(略,用來傳入路徑或urls),并修改源碼中獲取Filter的方法createFilterChainResolver()
?在其創建Filter實例之前插入代碼
ini.load(String);
?源碼:(此處檢查了是否有 urls和filter配置)
// only create a resolver if the "filters" or "urls" sections are defined: Ini.Section urls = ini.getSection(IniFilterChainResolverFactory.URLS); Ini.Section filters = ini.getSection(IniFilterChainResolverFactory.FILTERS); if (!CollectionUtils.isEmpty(urls) || !CollectionUtils.isEmpty(filters)) { // either the urls section or the filters section was defined. Go ahead and create the resolver: IniFilterChainResolverFactory factory = new IniFilterChainResolverFactory(ini, this.objects); resolver = factory.getInstance(); }
?修改后的代碼(此處需要注意我們邏輯中沒有 filter配置,這里就沒判斷)
//urls為符合 ini語法的字符串 例如 /user/login = anon String iniUrls = "[urls] " + urls; ini.load(iniUrls); // 此代碼前,在此處ini會被加載成類 // ini對象在此方法之前就存在,this.object則由父類中負責 IniFilterChainResolverFactory factory = new IniFilterChainResolverFactory(ini, this.objects); resolver = factory.getInstance();
?這里需要注意在調用 ini.load后原文件中的 [urls] 配置會被覆蓋,而當只有[urls] 但并沒有實際內容時并不會被覆蓋(沒試過空行,請注意)
?4.在完成這段代碼后發現代碼非常難看,shiro urls被配置到了java文件中,為了避免這個問題使用了NB-start直接帶的配置方式以及已經存在的 shiro.ini.urls屬性,將配置文件中的 urls傳入代碼中
?所以在NB中就成了這樣
//獲取配置文件中urls String urls = conf.get(ShiroEnvStarter.PROP_INIT_URLS, null); //urls為符合 ini語法的字符串 例如 /user/login = anon String iniUrls = "[urls] " + urls; ini.load(iniUrls); // 此代碼前,在此處ini會被加載成類 // ini對象在此方法之前就存在,this.object則由父類中負責 IniFilterChainResolverFactory factory = new IniFilterChainResolverFactory(ini, this.objects); resolver = factory.getInstance();
?在NB的application.properties配置文件中寫法為
shiro.ini.urls: /unathenticated = anon /user/login = anon #end
?這里還要手動@并感謝下 @wendal @nutzcn
?之前并不知道application.properties中多行的寫法
?至此,整個在代碼中覆蓋 shiro urls 配置的思路基本就完成了,只剩下一些類似于非空判斷參數獲取的代碼.在此實現下即可實現項目中Shiro main配置為統一文件,而urls配置為專用多帶帶文件
?之后要介紹的就是優化部分以及,完整代碼
三.優化(完全基于NB)?1.在使用中發現雖然現在 urls已經可以獨立文件配置,但多行之間并不可以寫注解(在NB層就不會讀取完整),并且和 shiro.ini中語法并不完全一樣.
?最后解決辦法為:在項目中添加另一個.ini的配置文件,并在項目中讀取ini文件并使用 ini.load加載
?2.在添加了ini配置文件后發現最好可以有一部分urls可以通用配置,另一部分可以獨立配置.
?最后解決方式為:添加兩個shiro-url.ini配置文件,并在代碼中讀取并拼接,在庫服務中添加,一個ini文件,并在每個獨立的服務中添加完全同路徑和名稱的文件,使用其打包時互相覆蓋的特性,達到獨立配置的目的,而另一個不進行覆蓋達到通用配置的目的.
?而在NB中通過在 starter源碼中添加新的配置達到url可以配置并傳入的目的.
@PropDoc(value = "urls過濾清單ini文件1路徑") public static final String PROP_INIT_URLS_PATH1 = "shiro.ini.urls.path1"; @PropDoc(value = "urls過濾清單ini文件2路徑") public static final String PROP_INIT_URLS_PATH2 = "shiro.ini.urls.path2";
?這里附上讀取并拼接兩個 ini的代碼
private boolean loadIniPath1ANd2(Ini ini) { String urlsAll = ""; String urls1 = readConfig(ShiroEnvStarter.PROP_INIT_URLS_PATH1); String urls2 = readConfig(ShiroEnvStarter.PROP_INIT_URLS_PATH2); urlsAll = urls1 + urls2; if (!urlsAll.equals("")) { String iniUrls = "[urls] " + urlsAll; log.info("shiro ini urls ---> " + iniUrls); // Ini ini = new Ini(); // ini.load(iniUrls); // Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME); // Log.info(section.toString()); // 注意這個代碼中這里load過一次了 ini.load(iniUrls); // 此處驗證了 ini并沒有全被覆蓋,只覆蓋了 加載的配置文件部分 // 如果新加載的內容中 只有 [main] 標簽不會被覆蓋,但是如果 [main]標簽下有內容 則會覆蓋之前的配置 // for (Entryentry : ini.entrySet()) { // jline.internal.Log.info(entry.getKey()); // for (Entry entryStr : entry.getValue().entrySet()) { // jline.internal.Log.info(entryStr); // } // } return true; } return false; } private String readConfig(String confPath) { String urls1 = ""; try { String path = conf.get(confPath, "").trim(); log.info("path:" + path); if (path != null && appContext.getResourceLoader().has(path)) { InputStream is = ResourceUtils.getInputStreamForPath("classpath:" + path); if (is != null) { urls1 = readIniFile(is); } } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return urls1; } private String readIniFile(InputStream is) throws IOException { // InputStreamReader reader =new InputStreamReader(new // FileInputStream(file),"UTF-8"); InputStreamReader reader = new InputStreamReader(is); BufferedReader br = new BufferedReader(reader); StringBuffer sbf = new StringBuffer(); while (true) { String str = br.readLine(); if (str != null) { sbf.append(str).append(" "); } else { break; } } br.close(); reader.close(); return sbf.toString(); }
?當然代碼中依舊有可以優化的地方,不過這里就先不寫了,嘿嘿
?不過至此已經達到能想到的最好的效果了,父子項目中 父項目配置 shiro main中驗證和DB,Redis的大部分通用配置,以及所有通用的urls過濾,而子類可以添加新的urls配置,并且各個子項目中 shiro配置并不沖突.
?至此整偏博客結束,如果其中有錯誤也請大家告訴我了~~
?下面是源碼部分,不看可以跳過了!~
四.源碼部分?starter源碼部分
?不包括starter中未修改的類
?ShiroEnvStarter.java
//添加常量 @PropDoc(value = "urls過濾清單ini文件1路徑") public static final String PROP_INIT_URLS_PATH1 = "shiro.ini.urls.path1"; @PropDoc(value = "urls過濾清單ini文件2路徑") public static final String PROP_INIT_URLS_PATH2 = "shiro.ini.urls.path2";
?NbShiroEnvironmentLoaderListener.java
//修改 import java.io.IOException; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import org.apache.shiro.ShiroException; import org.apache.shiro.config.ConfigurationException; import org.apache.shiro.util.ClassUtils; import org.apache.shiro.util.UnknownClassException; import org.apache.shiro.web.env.EnvironmentLoader; import org.apache.shiro.web.env.EnvironmentLoaderListener; import org.apache.shiro.web.env.IniWebEnvironment; import org.nutz.boot.AppContext; import org.nutz.ioc.impl.PropertiesProxy; import org.nutz.lang.Lang; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jline.internal.Log; public class NbShiroEnvironmentLoaderListener extends EnvironmentLoaderListener { private static final Logger log = LoggerFactory.getLogger(NbShiroEnvironmentLoaderListener.class); protected PropertiesProxy conf; protected AppContext appContext; @Override public void contextInitialized(ServletContextEvent sce) { PropertiesProxy conf = appContext.getConfigureLoader().get(); try { boolean hasUrlsPath = hasIniUrlsPath(conf, appContext); // 走原生API的shiro.ini文件嗎? String iniPath = conf.get("shiro.ini.path", "shiro.ini"); boolean hasIniPath = conf.has("shiro.ini.path") || appContext.getResourceLoader().has(iniPath); if (hasIniPath || (hasIniPath && hasUrlsPath)) { sce.getServletContext().setAttribute(EnvironmentLoader.CONFIG_LOCATIONS_PARAM, iniPath); super.contextInitialized(sce); return; } } catch (Exception e) { throw Lang.wrapThrow(e); } // 沒有配置文件 走nb(默認)配置 sce.getServletContext().setAttribute(ENVIRONMENT_CLASS_PARAM, NbResourceBasedWebEnvironment.class.getName()); super.contextInitialized(sce); } protected Class> determineWebEnvironmentClass(ServletContext servletContext) { // nb 默認配置 String className = servletContext.getInitParameter(ENVIRONMENT_CLASS_PARAM); if (className != null) { try { return ClassUtils.forName(className); } catch (UnknownClassException ex) { throw new ConfigurationException("Failed to load custom WebEnvironment class [" + className + "]", ex); } } else { try { boolean hasUrlsPath = hasIniUrlsPath(conf, appContext); // 如果有配置文件 String iniPath = conf.get("shiro.ini.path", "shiro.ini"); boolean hasIniPath = conf.has("shiro.ini.path") || appContext.getResourceLoader().has(iniPath); if (hasIniPath && hasUrlsPath) { return IniMixWebEnvironment.class; } else if (hasIniPath) { return IniWebEnvironment.class; } } catch (IOException e) { throw new ShiroException(e); } return NbResourceBasedWebEnvironment.class; } } private boolean hasIniUrlsPath(PropertiesProxy conf, AppContext appContext) throws IOException { String iniUrlsPath1 = conf.get(ShiroEnvStarter.PROP_INIT_URLS_PATH1, null); boolean hasIniUrlsPath1 = false; if (iniUrlsPath1 != null) { hasIniUrlsPath1 = (conf.has(ShiroEnvStarter.PROP_INIT_URLS_PATH1) || appContext.getResourceLoader().has(iniUrlsPath1)); } String iniUrlsPath2 = conf.get(ShiroEnvStarter.PROP_INIT_URLS_PATH2, null); boolean hasIniUrlsPath2 = false; if (iniUrlsPath2 != null) { hasIniUrlsPath2 = (conf.has(ShiroEnvStarter.PROP_INIT_URLS_PATH2) || appContext.getResourceLoader().has(iniUrlsPath2)); } if (hasIniUrlsPath1 || hasIniUrlsPath2) { return true; } return false; } }
基于 shiro原生實現的實現類
import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Map; import javax.servlet.ServletContext; import org.apache.shiro.config.ConfigurationException; import org.apache.shiro.config.Ini; import org.apache.shiro.config.IniFactorySupport; import org.apache.shiro.io.ResourceUtils; import org.apache.shiro.util.CollectionUtils; import org.apache.shiro.util.Destroyable; import org.apache.shiro.util.Initializable; import org.apache.shiro.util.StringUtils; import org.apache.shiro.web.config.IniFilterChainResolverFactory; import org.apache.shiro.web.config.WebIniSecurityManagerFactory; import org.apache.shiro.web.env.IniWebEnvironment; import org.apache.shiro.web.env.ResourceBasedWebEnvironment; import org.apache.shiro.web.env.WebEnvironment; import org.apache.shiro.web.filter.mgt.FilterChainResolver; import org.apache.shiro.web.mgt.WebSecurityManager; import org.apache.shiro.web.util.WebUtils; import org.nutz.boot.AppContext; import org.nutz.ioc.Ioc; import org.nutz.ioc.impl.PropertiesProxy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * {@link WebEnvironment} implementation configured by an {@link Ini} instance * or {@code Ini} resource locations. * * 代碼主要實現部分由shiro IniWebEnvironment源碼抄過來的
* 修改了 createFilterChainResolver 方法,讓 ini又load了一個 urls 配置
* 目前從現象看 ini.load 似乎不會覆蓋整個配置 * * @since 1.2 */ public class IniMixWebEnvironment extends ResourceBasedWebEnvironment implements Initializable, Destroyable { // *********非源碼部分********** protected AppContext appContext; protected Ioc ioc; protected PropertiesProxy conf; // **************************** public static final String DEFAULT_WEB_INI_RESOURCE_PATH = "/WEB-INF/shiro.ini"; private static final Logger log = LoggerFactory.getLogger(IniWebEnvironment.class); /** * The Ini that configures this WebEnvironment instance. */ private Ini ini; /** * Initializes this instance by resolving any potential (explicit or * resource-configured) {@link Ini} configuration and calling * {@link #configure() configure} for actual instance configuration. */ public void init() { // *********非源碼部分********** appContext = AppContext.getDefault(); ioc = appContext.getIoc(); conf = appContext.getConfigureLoader().get(); // **************************** Ini ini = getIni(); String[] configLocations = getConfigLocations(); if (log.isWarnEnabled() && !CollectionUtils.isEmpty(ini) && configLocations != null && configLocations.length > 0) { log.warn("Explicit INI instance has been provided, but configuration locations have also been " + "specified. The {} implementation does not currently support multiple Ini config, but this may " + "be supported in the future. Only the INI instance will be used for configuration.", IniWebEnvironment.class.getName()); } if (CollectionUtils.isEmpty(ini)) { log.debug("Checking any specified config locations."); ini = getSpecifiedIni(configLocations); } if (CollectionUtils.isEmpty(ini)) { log.debug("No INI instance or config locations specified. Trying default config locations."); ini = getDefaultIni(); } if (CollectionUtils.isEmpty(ini)) { String msg = "Shiro INI configuration was either not found or discovered to be empty/unconfigured."; throw new ConfigurationException(msg); } setIni(ini); configure(); } protected void configure() { this.objects.clear(); WebSecurityManager securityManager = createWebSecurityManager(); setWebSecurityManager(securityManager); FilterChainResolver resolver = createFilterChainResolver(); if (resolver != null) { setFilterChainResolver(resolver); } } protected Ini getSpecifiedIni(String[] configLocations) throws ConfigurationException { Ini ini = null; if (configLocations != null && configLocations.length > 0) { if (configLocations.length > 1) { log.warn( "More than one Shiro .ini config location has been specified. Only the first will be " + "used for configuration as the {} implementation does not currently support multiple " + "files. This may be supported in the future however.", IniWebEnvironment.class.getName()); } // required, as it is user specified: ini = createIni(configLocations[0], true); } return ini; } protected Ini getDefaultIni() { Ini ini = null; String[] configLocations = getDefaultConfigLocations(); if (configLocations != null) { for (String location : configLocations) { ini = createIni(location, false); if (!CollectionUtils.isEmpty(ini)) { log.debug("Discovered non-empty INI configuration at location "{}". Using for configuration.", location); break; } } } return ini; } /** * Creates an {@link Ini} instance reflecting the specified path, or * {@code null} if the path does not exist and is not required. * * If the path is required and does not exist or is empty, a * {@link ConfigurationException} will be thrown. * * @param configLocation the resource path to load into an {@code Ini} instance. * @param required if the path must exist and be converted to a non-empty * {@link Ini} instance. * @return an {@link Ini} instance reflecting the specified path, or * {@code null} if the path does not exist and is not required. * @throws ConfigurationException if the path is required but results in a null * or empty Ini instance. */ protected Ini createIni(String configLocation, boolean required) throws ConfigurationException { Ini ini = null; if (configLocation != null) { ini = convertPathToIni(configLocation, required); } if (required && CollectionUtils.isEmpty(ini)) { String msg = "Required configuration location "" + configLocation + "" does not exist or did not " + "contain any INI configuration."; throw new ConfigurationException(msg); } return ini; } protected FilterChainResolver createFilterChainResolver() { FilterChainResolver resolver = null; Ini ini = getIni(); if (!CollectionUtils.isEmpty(ini)) { // only create a resolver if the "filters" or "urls" sections are defined: // Ini.Section urls = ini.getSection(IniFilterChainResolverFactory.URLS); // Ini.Section filters = ini.getSection(IniFilterChainResolverFactory.FILTERS); // *********非源碼部分********** // boolean loadUrls = loadIniUrls(ini); boolean loadUrls = loadIniPath1ANd2(ini); if (loadUrls) { // **************************** // if (!CollectionUtils.isEmpty(urls) || !CollectionUtils.isEmpty(filters)) { // either the urls section or the filters section was defined. Go ahead and create the resolver: IniFilterChainResolverFactory factory = new IniFilterChainResolverFactory(ini, this.objects); resolver = factory.getInstance(); } } return resolver; } // *********非源碼部分********** private boolean loadIniPath1ANd2(Ini ini) { String urlsAll = ""; String urls1 = readConfig(ShiroEnvStarter.PROP_INIT_URLS_PATH1); String urls2 = readConfig(ShiroEnvStarter.PROP_INIT_URLS_PATH2); urlsAll = urls1 + urls2; if (!urlsAll.equals("")) { String iniUrls = "[urls] " + urlsAll; log.info("shiro ini urls ---> " + iniUrls); // Ini ini = new Ini(); // ini.load(iniUrls); // Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME); // Log.info(section.toString()); ini.load(iniUrls); // 此處驗證了 ini并沒有全被覆蓋,只覆蓋了 加載的配置文件部分 // 如果新加載的內容中 只有 [main] 標簽不會被覆蓋,但是如果 [main]標簽下有內容 則會覆蓋之前的配置 // for (Entryentry : ini.entrySet()) { // jline.internal.Log.info(entry.getKey()); // for (Entry entryStr : entry.getValue().entrySet()) { // jline.internal.Log.info(entryStr); // } // } return true; } return false; } private String readConfig(String confPath) { String urls1 = ""; try { String path = conf.get(confPath, "").trim(); log.info("path:" + path); if (path != null && appContext.getResourceLoader().has(path)) { InputStream is = ResourceUtils.getInputStreamForPath("classpath:" + path); if (is != null) { urls1 = readIniFile(is); } } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return urls1; } private String readIniFile(InputStream is) throws IOException { // InputStreamReader reader =new InputStreamReader(new // FileInputStream(file),"UTF-8"); InputStreamReader reader = new InputStreamReader(is); BufferedReader br = new BufferedReader(reader); StringBuffer sbf = new StringBuffer(); while (true) { String str = br.readLine(); if (str != null) { sbf.append(str).append(" "); } else { break; } } br.close(); reader.close(); return sbf.toString(); } private boolean loadIniUrls(Ini ini) { // 使用了 原 start中定義的 shiro.ini.urls String config = conf.get(ShiroEnvStarter.PROP_INIT_URLS, "").trim(); if (config != null && !config.equals("")) { String iniUrls = "[urls] " + config; log.info("shiro ini urls ---> " + iniUrls); // Ini ini = new Ini(); // ini.load(iniUrls); // Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME); // Log.info(section.toString()); ini.load(iniUrls); return true; } return false; } // **************************** protected WebSecurityManager createWebSecurityManager() { WebIniSecurityManagerFactory factory; Ini ini = getIni(); if (CollectionUtils.isEmpty(ini)) { factory = new WebIniSecurityManagerFactory(); } else { factory = new WebIniSecurityManagerFactory(ini); } WebSecurityManager wsm = (WebSecurityManager) factory.getInstance(); // SHIRO-306 - get beans after they"ve been created (the call was before the // factory.getInstance() call, // which always returned null. Map beans = factory.getBeans(); if (!CollectionUtils.isEmpty(beans)) { this.objects.putAll(beans); } return wsm; } /** * Returns an array with two elements, {@code /WEB-INF/shiro.ini} and * {@code classpath:shiro.ini}. * * @return an array with two elements, {@code /WEB-INF/shiro.ini} and * {@code classpath:shiro.ini}. */ protected String[] getDefaultConfigLocations() { return new String[] { DEFAULT_WEB_INI_RESOURCE_PATH, IniFactorySupport.DEFAULT_INI_RESOURCE_PATH }; } /** * Converts the specified file path to an {@link Ini} instance. * * If the path does not have a resource prefix as defined by * {@link org.apache.shiro.io.ResourceUtils#hasResourcePrefix(String)}, the path * is expected to be resolvable by the {@code ServletContext} via * {@link javax.servlet.ServletContext#getResourceAsStream(String)}. * * @param path the path of the INI resource to load into an INI instance. * @param required if the specified path must exist * @return an INI instance populated based on the given INI resource path. */ private Ini convertPathToIni(String path, boolean required) { // TODO - this logic is ugly - it"d be ideal if we had a Resource API to // polymorphically encaspulate this behavior Ini ini = null; if (StringUtils.hasText(path)) { InputStream is = null; // SHIRO-178: Check for servlet context resource and not only resource paths: if (!ResourceUtils.hasResourcePrefix(path)) { is = getServletContextResourceStream(path); } else { try { is = ResourceUtils.getInputStreamForPath(path); } catch (IOException e) { if (required) { throw new ConfigurationException(e); } else { if (log.isDebugEnabled()) { log.debug("Unable to load optional path "" + path + "".", e); } } } } if (is != null) { ini = new Ini(); ini.load(is); } else { if (required) { throw new ConfigurationException("Unable to load resource path "" + path + """); } } } return ini; } // TODO - this logic is ugly - it"d be ideal if we had a Resource API to // polymorphically encaspulate this behavior private InputStream getServletContextResourceStream(String path) { InputStream is = null; path = WebUtils.normalize(path); ServletContext sc = getServletContext(); if (sc != null) { is = sc.getResourceAsStream(path); } return is; } /** * Returns the {@code Ini} instance reflecting this WebEnvironment"s * configuration. * * @return the {@code Ini} instance reflecting this WebEnvironment"s * configuration. */ public Ini getIni() { return this.ini; } /** * Allows for configuration via a direct {@link Ini} instance instead of via * {@link #getConfigLocations() config locations}. * * If the specified instance is null or empty, the fallback/default * resource-based configuration will be used. * * @param ini the ini instance to use for creation. */ public void setIni(Ini ini) { this.ini = ini; } }
如果以后想到什么再補充吧
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/76484.html
摘要:的很容易反映出常見的工作流程。權限檢查是執行授權的另一種方式。在安全框架領域提供了一些獨特的東西一致的會話,可用于任何應用程序和任何架構層。 Apache Shiro?是一個功能強大且易于使用的Java安全框架,可執行身份驗證,授權,加密和會話管理。借助Shiro易于理解的API,可以快速輕松地保護任何應用程序 - 從最小的移動應用程序到最大的Web和企業應用程序。 1. Apache S...
摘要:細粒度權限管理就是數據級別的權限管理。張三只能查看行政部的用戶信息,李四只能查看開發部門的用戶信息。比如通過的攔截器實現授權。 前言 本文主要講解的知識點有以下: 權限管理的基礎知識 模型 粗粒度和細粒度的概念 回顧URL攔截的實現 Shiro的介紹與簡單入門 一、Shiro基礎知識 在學習Shiro這個框架之前,首先我們要先了解Shiro需要的基礎知識:權限管理 1.1什...
摘要:表示對用戶資源進行操作,相當于,對所有用戶資源實例進行操作。與整合,實際上的操作都是通過過濾器來干的。將安全管理器交由工廠來進行管理。在過濾器鏈中設置靜態資源不攔截。 前言 本文主要講解的知識點有以下: Shiro授權的方式簡單介紹 與Spring整合 初始Shiro過濾器 一、Shiro授權 上一篇我們已經講解了Shiro的認證相關的知識了,現在我們來弄Shiro的授權 Shir...
摘要:是什么是功能強大簡單易用的安全框架,核心功能包括認證授權加密以及管理。的主要作用就是用來執行認證和授權的邏輯,它其實就相當于與安全數據用戶賬號密碼角色權限之間進行交互的橋梁。至此,的三個核心概念已經介紹完畢。 1、Shiro是什么 Shiro是功能強大、簡單易用的Java安全框架,核心功能包括:認證、授權、加密以及Session管理。Shiro的應用范圍很廣泛,小型移動端應用、大型We...
摘要:而一個哈希字符串就是根據文件內容產生的簽名,每當文件內容發生更改時,哈希串也就發生了更改,文件名也就隨之更改。很顯然這不是我們需要的,如果文件內容發生了更改,的打包文件的哈希應該發生變化,但是不應該。前言 隨著前端代碼需要處理的業務越來越繁重,我們不得不面臨的一個問題是前端的代碼體積也變得越來越龐大。這造成無論是在調式還是在上線時都需要花長時間等待編譯完成,并且用戶也不得不花額外的時間和帶寬...
閱讀 1447·2021-09-28 09:44
閱讀 2510·2021-09-28 09:36
閱讀 1161·2021-09-08 09:35
閱讀 1988·2019-08-29 13:50
閱讀 816·2019-08-29 13:29
閱讀 1136·2019-08-29 13:15
閱讀 1728·2019-08-29 13:00
閱讀 2994·2019-08-26 16:16