Apache Shiro???????????????SecurityManager?????????
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Apache Shiro???????????????SecurityManager?????????相关的知识,希望对你有一定的参考价值。
?????????ror ?????? ????????? deb fir cto scanner transient select
??????Shiro(v1.2+)???SecurityManager??????????????????????????????????????????????????????main?????????????????????Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
???????????????classpath????????????shiro.ini???????????????SecurityManager????????????web?????????????????????????????????????????????????????????????????????
???web?????????????????????????????????Listener??????SecurityManager???????????????Listener???????????????????????????Listener???shrio-web.jar??????
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
EnvironmentLoaderListener???????????????????????????????????????
EnvironmentLoader????????????????????????????????????????????????????????????Shiro????????????org.apache.shiro.web.mgt.WebSecurityManager?????????ServletContext??????
????????????Shiro??????????????????web.xml????????????????????????????????????shiroEnvironmentClass?????????shiroConfigLocations???????????????Shiro????????????????????????????????????????????????????????????????????????????????????
shiroEnvironmentClass??????????????????WebEnvironment?????????????????????????????????IniWebEnvironment???
shiroConfigLocations?????????shiro?????????????????????????????????????????????????????????/WEB-INF/shiro.ini???????????????????????????classpath:shiro.ini???
public class EnvironmentLoaderListener extends EnvironmentLoader implements ServletContextListener {
/**
* Initializes the Shiro {@code WebEnvironment} and binds it to the {@code ServletContext} at application
* startup for future reference.
*
* @param sce the ServletContextEvent triggered upon application startup
*/
public void contextInitialized(ServletContextEvent sce) {
initEnvironment(sce.getServletContext());
}
/**
* Destroys any previously created/bound {@code WebEnvironment} instance created by
* the {@link #contextInitialized(javax.servlet.ServletContextEvent)} method.
*
* @param sce the ServletContextEvent triggered upon application shutdown
*/
public void contextDestroyed(ServletContextEvent sce) {
destroyEnvironment(sce.getServletContext());
}
}
public class EnvironmentLoader {
public WebEnvironment initEnvironment(ServletContext servletContext) throws IllegalStateException {
if (servletContext.getAttribute(ENVIRONMENT_ATTRIBUTE_KEY) != null) {
String msg = "There is already a Shiro environment associated with the current ServletContext. " +
"Check if you have multiple EnvironmentLoader* definitions in your web.xml!";
throw new IllegalStateException(msg);
}
servletContext.log("Initializing Shiro environment");
log.info("Starting Shiro environment initialization.");
long startTime = System.currentTimeMillis();
try {
WebEnvironment environment = createEnvironment(servletContext);
servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY,environment);
log.debug("Published WebEnvironment as ServletContext attribute with name [{}]",
ENVIRONMENT_ATTRIBUTE_KEY);
if (log.isInfoEnabled()) {
long elapsed = System.currentTimeMillis() - startTime;
log.info("Shiro environment initialized in {} ms.", elapsed);
}
return environment;
} catch (RuntimeException ex) {
log.error("Shiro environment initialization failed", ex);
servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY, ex);
throw ex;
} catch (Error err) {
log.error("Shiro environment initialization failed", err);
servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY, err);
throw err;
}
}
protected WebEnvironment createEnvironment(ServletContext sc) {
//??????WebEnvironment???????????????????????????
WebEnvironment webEnvironment = determineWebEnvironment(sc);
if (!MutableWebEnvironment.class.isInstance(webEnvironment)) {
throw new ConfigurationException("Custom WebEnvironment class [" + webEnvironment.getClass().getName() +
"] is not of required type [" + MutableWebEnvironment.class.getName() + "]");
}
String configLocations = sc.getInitParameter(CONFIG_LOCATIONS_PARAM);
boolean configSpecified = StringUtils.hasText(configLocations);
if (configSpecified && !(ResourceConfigurable.class.isInstance(webEnvironment))) {
String msg = "WebEnvironment class [" + webEnvironment.getClass().getName() + "] does not implement the " +
ResourceConfigurable.class.getName() + "interface. This is required to accept any " +
"configured " + CONFIG_LOCATIONS_PARAM + "value(s).";
throw new ConfigurationException(msg);
}
MutableWebEnvironment environment = (MutableWebEnvironment) webEnvironment;
//???????????????ServletContext??????
environment.setServletContext(sc);
//?????????web.xml???????????????????????????????????????????????????environment???
if (configSpecified && (environment instanceof ResourceConfigurable)) {
((ResourceConfigurable) environment).setConfigLocations(configLocations);
}
//??????????????????????????????
customizeEnvironment(environment);
//??????environment???init???????????????environment??????
LifecycleUtils.init(environment);
return environment;
}
protected WebEnvironment determineWebEnvironment(ServletContext servletContext) {
//???ServletContext??????????????????WebEnvironment?????????--shiroEnvironmentClass?????????????????????????????????
Class<? extends WebEnvironment> webEnvironmentClass = webEnvironmentClassFromServletContext(servletContext);
WebEnvironment webEnvironment = null;
// ????????????Java???ServiceLoader?????????WebEnvironment????????????
if (webEnvironmentClass == null) {
webEnvironment = webEnvironmentFromServiceLoader();
}
// ??????????????????????????????????????????????????????WebEnvironment?????????IniWebEnvironment
if (webEnvironmentClass == null && webEnvironment == null) {
webEnvironmentClass = getDefaultWebEnvironmentClass();
}
// ??????WebEnvironment?????????
if (webEnvironmentClass != null) {
webEnvironment = (WebEnvironment) ClassUtils.newInstance(webEnvironmentClass);
}
return webEnvironment;
}
private WebEnvironment webEnvironmentFromServiceLoader() {
WebEnvironment webEnvironment = null;
/*
* ??????Java???ServiceLoader???????????????WebEnvironment????????????(??????jar??????META-INF??????services?????????????????????)???
* ???????????????services????????????????????????org.apache.shiro.web.env.WebEnvironment???????????????????????????????????????WebEnvironment????????????????????????
* ??????????????????????????????????????????????????????????????????????????????
* */
ServiceLoader<WebEnvironment> serviceLoader = ServiceLoader.load(WebEnvironment.class);
Iterator<WebEnvironment> iterator = serviceLoader.iterator();
// ??????????????????????????????
if (iterator.hasNext()) {
webEnvironment = iterator.next();
}
// ??????????????????????????????????????????
if (iterator.hasNext()) {
List<String> allWebEnvironments = new ArrayList<String>();
allWebEnvironments.add(webEnvironment.getClass().getName());
while (iterator.hasNext()) {
allWebEnvironments.add(iterator.next().getClass().getName());
}
throw new ConfigurationException("ServiceLoader for class [" + WebEnvironment.class + "] returned more then one " +
"result. ServiceLoader must return zero or exactly one result for this class. Select one using the " +
"servlet init parameter ???"+ ENVIRONMENT_CLASS_PARAM +"???. Found: " + allWebEnvironments);
}
return webEnvironment;
}
}
?????????????????????WebEnvironment?????????????????????????????????
1??????ServletContext??????????????????
2??????jar??????????????????
3??????????????????IniWebEnvironment
?????????WebEnvironment?????????????????????????????????????????????????????????init??????????????????????????????????????????IniWebEnvironment???
public class IniWebEnvironment extends ResourceBasedWebEnvironment implements Initializable, Destroyable {
public static final String DEFAULT_WEB_INI_RESOURCE_PATH = "/WEB-INF/shiro.ini";
public static final String FILTER_CHAIN_RESOLVER_NAME = "filterChainResolver";
private static final Logger log = LoggerFactory.getLogger(IniWebEnvironment.class);
/**
* The Ini that configures this WebEnvironment instance.
*/
private Ini ini;
private WebIniSecurityManagerFactory factory;
public IniWebEnvironment() {
//?????????WebIniSecurityManagerFactory??????
factory = new WebIniSecurityManagerFactory();
}
/**
* ??????????????????
*/
public void init() {
//??????shiiro.ini??????????????????????????????Ini??????
setIni(parseConfig());
//??????Ini???????????????WebIniSecurityManagerFactory??????WebSecurityManager??????
configure();
}
}
protected Ini parseConfig() {
//?????????????????????????????????null
Ini ini = getIni();
//????????????????????????????????????????????????web.xml??????????????????,?????????????????????????????????EnvironmentLoader????????????
String[] configLocations = getConfigLocations();
if (log.isWarnEnabled() && !CollectionUtils.isEmpty(ini) &&
configLocations != null && configLocations.length > 0) {
//??????Ini????????????????????????configLocations????????????,??????????????????
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??????
ini = getSpecifiedIni(configLocations);
}
if (CollectionUtils.isEmpty(ini)) {
log.debug("No INI instance or config locations specified. Trying default config locations.");
/*
* ???????????????web.xml?????????????????????????????????????????????????????????????????????
* 1,/WEB-INF/shiro.ini
* 2,classpath:shiro.ini
* */
ini = getDefaultIni();
}
/*
* ?????????????????????????????????getFrameworkIni???????????????Ini???????????????????????????Ini????????????.
* getFrameworkIni?????????????????????null????????????????????????????????????????????????Ini??????
* */
ini = mergeIni(getFrameworkIni(), ini);
if (CollectionUtils.isEmpty(ini)) {
String msg = "Shiro INI configuration was either not found or discovered to be empty/unconfigured.";
throw new ConfigurationException(msg);
}
return ini;
}
/**
* ????????????????????????Ini????????????
* */
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;
}
/**
* ????????????????????????????????????????????????????????????????????????Ini???????????????load??????????????????Ini??????
* */
private Ini convertPathToIni(String path, boolean required) {
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;
}
?????????Ini????????????????????????
public class Ini implements Map<String, Ini.Section> {
private static transient final Logger log = LoggerFactory.getLogger(Ini.class);
public static final String DEFAULT_SECTION_NAME = ""; //empty string means the first unnamed section
public static final String DEFAULT_CHARSET_NAME = "UTF-8";
public static final String COMMENT_POUND = "#";
public static final String COMMENT_SEMICOLON = ";";
public static final String SECTION_PREFIX = "[";
public static final String SECTION_SUFFIX = "]";
protected static final char ESCAPE_TOKEN = ???\???;
private final Map<String, Section> sections;
/**
* Creates a new empty {@code Ini} instance.
*/
public Ini() {
this.sections = new LinkedHashMap<String, Section>();
}
public void load(InputStream is) throws ConfigurationException {
if (is == null) {
throw new NullPointerException("InputStream argument cannot be null.");
}
InputStreamReader isr;
try {
isr = new InputStreamReader(is, DEFAULT_CHARSET_NAME);
} catch (UnsupportedEncodingException e) {
throw new ConfigurationException(e);
}
load(isr);
}
public void load(Reader reader) {
Scanner scanner = new Scanner(reader);
try {
load(scanner);
} finally {
try {
scanner.close();
} catch (Exception e) {
log.debug("Unable to cleanly close the InputStream scanner. Non-critical - ignoring.", e);
}
}
}
public void load(Scanner scanner) {
String sectionName = DEFAULT_SECTION_NAME;
StringBuilder sectionContent = new StringBuilder();
//?????????????????????
while (scanner.hasNextLine()) {
String rawLine = scanner.nextLine();
//?????????????????????
String line = StringUtils.clean(rawLine);
if (line == null || line.startsWith(COMMENT_POUND) || line.startsWith(COMMENT_SEMICOLON)) {
//?????????????????????
continue;
}
//??????section?????????????????? [main] ????????????????????????main???
String newSectionName = getSectionName(line);
if (newSectionName != null) {
//??????section????????????????????????????????????section??????
addSection(sectionName, sectionContent);
//????????????section??????StringBuilder????????????????????????section???????????????
sectionContent = new StringBuilder();
sectionName = newSectionName;
if (log.isDebugEnabled()) {
log.debug("Parsing " + SECTION_PREFIX + sectionName + SECTION_SUFFIX);
}
} else {
//??????????????????
sectionContent.append(rawLine).append("
");
}
}
//??????Section???????????????
addSection(sectionName, sectionContent);
}
private void addSection(String name, StringBuilder content) {
if (content.length() > 0) {
String contentString = content.toString();
String cleaned = StringUtils.clean(contentString);
if (cleaned != null) {
//??????Section???????????????????????????
Section section = new Section(name, contentString);
if (!section.isEmpty()) {
//???????????????????????????Section??????
sections.put(name, section);
}
}
}
}
public static class Section implements Map<String, String> {
private final String name;
private final Map<String, String> props;
/*
* ??????????????????????????????????????????????????????props?????????
* */
private Section(String name, String sectionContent) {
if (name == null) {
throw new NullPointerException("name");
}
this.name = name;
Map<String,String> props;
if (StringUtils.hasText(sectionContent) ) {
props = toMapProps(sectionContent);
} else {
props = new LinkedHashMap<String,String>();
}
if ( props != null ) {
this.props = props;
} else {
this.props = new LinkedHashMap<String,String>();
}
}
}
}
????????????IniWebEnvironment??????????????????????????????????????????Ini?????????????????????????????????????????????????????????Section????????????????????????????????????Ini???????????????WebSecurityManager?????????????????????IniWebEnvironment ???configure??????
public class IniWebEnvironment extends ResourceBasedWebEnvironment implements Initializable, Destroyable {
protected void configure() {
//Map<String, Object>??????
this.objects.clear();
WebSecurityManager securityManager = createWebSecurityManager();
setWebSecurityManager(securityManager);
FilterChainResolver resolver = createFilterChainResolver();
if (resolver != null) {
setFilterChainResolver(resolver);
}
}
protected Map<String, Object> getDefaults() {
Map<String, Object> defaults = new HashMap<String, Object>();
defaults.put(FILTER_CHAIN_RESOLVER_NAME, new IniFilterChainResolverFactory());
return defaults;
}
protected WebSecurityManager createWebSecurityManager() {
//??????????????????Ini??????
Ini ini = getIni();
if (!CollectionUtils.isEmpty(ini)) {
factory.setIni(ini);
}
Map<String, Object> defaults = getDefaults();
if (!CollectionUtils.isEmpty(defaults)) {
factory.setDefaults(defaults);
}
//???WebIniSecurityManagerFactory???????????????WebSecurityManager
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<String, ?> beans = factory.getBeans();
if (!CollectionUtils.isEmpty(beans)) {
this.objects.putAll(beans);
}
return wsm;
}
}
????????????WebIniSecurityManagerFactory???getInstance???????????????
????????????????????????getInstance??????????????????????????????????????????AbstractFactory??????getInstance??????
public abstract class AbstractFactory<T> implements Factory<T> {
public T getInstance() {
T instance;
if (isSingleton()) {
if (this.singletonInstance == null) {
this.singletonInstance = createInstance();
}
instance = this.singletonInstance;
} else {
instance = createInstance();
}
if (instance == null) {
String msg = "Factory ???createInstance??? implementation returned a null object.";
throw new IllegalStateException(msg);
}
return instance;
}
/*
* ??????(IniFactorySupport)???????????????????????????
* */
protected abstract T createInstance();
}
public abstract class IniFactorySupport<T> extends AbstractFactory<T> {
public T createInstance() {
/*
* ??????Ini????????????????????????????????????
* ??????ini???????????????????????????????????????????????????Ini??????
* */
Ini ini = resolveIni();
T instance;
if (CollectionUtils.isEmpty(ini)) {
//??????Ini?????????????????????????????????(IniSecurityManagerFactory)???????????????SecurityManager????????????
log.debug("No populated Ini available. Creating a default instance.");
instance = createDefaultInstance();
if (instance == null) {
String msg = getClass().getName() + " implementation did not return a default instance in " +
"the event of a null/empty Ini configuration. This is required to support the " +
"Factory interface. Please check your implementation.";
throw new IllegalStateException(msg);
}
} else {
log.debug("Creating instance from Ini [" + ini + "]");
//????????????(IniSecurityManagerFactory)?????????Ini????????????????????????SecurityManager??????
instance = createInstance(ini);
if (instance == null) {
String msg = getClass().getName() + " implementation did not return a constructed instance from " +
"the createInstance(Ini) method implementation.";
throw new IllegalStateException(msg);
}
}
return instance;
}
protected abstract T createInstance(Ini ini);
protected abstract T createDefaultInstance();
}
public class IniSecurityManagerFactory extends IniFactorySupport<SecurityManager> {
public static final String MAIN_SECTION_NAME = "main";
public static final String SECURITY_MANAGER_NAME = "securityManager";
public static final String INI_REALM_NAME = "iniRealm";
private ReflectionBuilder builder;
public IniSecurityManagerFactory() {
this.builder = new ReflectionBuilder();
}
//?????????SecurityManager??????????????????WebIniSecurityManagerFactory?????????????????????DefaultWebSecurityManager???
protected SecurityManager createDefaultInstance() {
return new DefaultSecurityManager();
}
//??????Ini?????????SecurityManager??????
protected SecurityManager createInstance(Ini ini) {
if (CollectionUtils.isEmpty(ini)) {
throw new NullPointerException("Ini argument cannot be null or empty.");
}
SecurityManager securityManager = createSecurityManager(ini);
if (securityManager == null) {
String msg = SecurityManager.class + " instance cannot be null.";
throw new ConfigurationException(msg);
}
return securityManager;
}
private SecurityManager createSecurityManager(Ini ini) {
return createSecurityManager(ini, getConfigSection(ini));
}
//??????[main]???????????????????????????????????????????????????
private Ini.Section getConfigSection(Ini ini) {
Ini.Section mainSection = ini.getSection(MAIN_SECTION_NAME);
if (CollectionUtils.isEmpty(mainSection)) {
//try the default:
mainSection = ini.getSection(Ini.DEFAULT_SECTION_NAME);
}
return mainSection;
}
@SuppressWarnings({"unchecked"})
private SecurityManager createSecurityManager(Ini ini, Ini.Section mainSection) {
/*
* ?????????createDefaults?????????WebIniSecurityManagerFactory?????????
* ????????????????????????????????????createDefaults???????????????????????????????????????????????????Filter?????????
*
* ????????????????????????ReflectionBuilder?????????objects???Map?????????????????????????????????????????????SecurityManager???Realm??????????????????Filter?????????
*
* ?????????createDefaults?????????Map????????????ReflectionBuilder?????????objects???Map???????????????
* */
getReflectionBuilder().setObjects(createDefaults(ini, mainSection));
//??????ReflectionBuilder?????????????????????????????????????????????objects???????????????????????????????????????init??????,????????????objects?????????
Map<String, ?> objects = buildInstances(mainSection);
//?????????ReflectionBuilder???????????????SecurityManager???????????????
SecurityManager securityManager = getSecurityManagerBean();
/*
* ??????securityManager??????RealmSecurityManager???????????????true???
* ?????????RealmSecurityManager???????????????????????????Realm??????????????????true???
* ????????????false
* */
boolean autoApplyRealms = isAutoApplyRealms(securityManager);
if (autoApplyRealms) {
//???????????????Realms?????????Realm???RealmFactory?????????
Collection<Realm> realms = getRealms(objects);
if (!CollectionUtils.isEmpty(realms)) {
//??????securityManager??????RealmSecurityManager?????????????????????????????????securityManager??????Realms
applyRealmsToSecurityManager(realms, securityManager);
}
}
return securityManager;
}
}
?????????SecurityManager?????????????????????????????????IniWebEnvironment?????????objects[Map]???
public class IniWebEnvironment extends ResourceBasedWebEnvironment implements Initializable, Destroyable {
protected void configure() {
//Map<String, Object>??????
this.objects.clear();
WebSecurityManager securityManager = createWebSecurityManager();
setWebSecurityManager(securityManager);
//??????shiro.ini?????????????????????filters??? ??? ???urls?????????Filter?????????objects?????????
FilterChainResolver resolver = createFilterChainResolver();
if (resolver != null) {
setFilterChainResolver(resolver);
}
}
}
?????????Shiro??????????????????????????????EnvironmentLoaderListener ???????????????IniWebEnvironment???????????????ServletContext?????????????????????
??????????????????
???????????????????????????EnvironmentLoaderListener????????????????????????WebEnvironment???????????????????????????????????????ServletContext???
1?????????WebEnvironment??????
1?????????web.xml?????????????????????shiroEnvironmentClass
2?????????ServiceLoader????????????jar???????????????
3??????????????????IniWebEnvironment??????
2?????????WebEnvironment???init???????????????WebEnvironment??????
??????WebEnvironment???????????????????????????WebIniSecurityManagerFactory??????factory???
1???????????????????????????????????????shiro.ini????????????Ini??????
2??????Ini???????????????factory???ini??????
3???????????????IniFilterChainResolverFactory?????????factory???defaultBeans(Map)??????
4?????????factory???getInstance????????????SecurityManager??????
--??????Ini??????????????????????????????Realm?????????????????????SecurityManager??????
5??????SecurityManager?????????objects(Map)?????????WebEnvironment???objects??????
?????????SecurityManager??? DefaultWebSecurityManager
?????????????????????Session???Realm?????????
以上是关于Apache Shiro???????????????SecurityManager?????????的主要内容,如果未能解决你的问题,请参考以下文章