Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

The creation of Subject for Apache Shiro Source Code interpretation

2025-03-31 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/03 Report--

Subject is a very important object in Shiro, which can be simply understood as "current user". First, let's take a look at the inheritance relationship of Subject.

Whether it is a web application or an ordinary application, we have obtained the Subject object and used Session in a method by

Subject currentUser = org.apache.shiro.SecurityUtils.getSubject (); if (! currentUser.isAuthenticated ()) {UsernamePasswordToken token = new UsernamePasswordToken ("user", "password"); token.setRememberMe (true); try {currentUser.login (token); Session session = currentUser.getSession (); session.setAttribute ("key", "value") } catch (UnknownAccountException uae) {/ / user does not exist} catch (IncorrectCredentialsException ice) {/ / password error} catch (LockedAccountException lae) {/ / user is locked} catch (AuthenticationException ae) {/ / unexpected condition-error?}}

The SecurityUtils is located in shiro-core.jar

Login authentication can be done with two simple lines of code, or you can use Session. It looks very simple, but there may be many complexities hidden behind it. Let's take a look.

/ * * Accesses the currently accessible {@ code Subject} for the calling code depending on runtime environment. * * @ since 0.2 * / public abstract class SecurityUtils {public static Subject getSubject () {Subject subject = ThreadContext.getSubject (); if (subject = = null) {subject = (new Subject.Builder ()) .buildSubject (); ThreadContext.bind (subject);} return subject;}}

The Subject is first obtained directly from the TreadContext, and if not, it is created within the Subject, and then bound to the ThreadContext. So let's move on to the definition of ThreadContext.

Public abstract class ThreadContext {public static final String SUBJECT_KEY = ThreadContext.class.getName () + "_ SUBJECT_KEY"; private static final ThreadLocal resources = new InheritableThreadLocalMap (); public static Subject getSubject () {return (Subject) get (SUBJECT_KEY) } public static Object get (Object key) {if (log.isTraceEnabled ()) {String msg = "get ()-in thread [" + Thread.currentThread (). GetName () + "]"; log.trace (msg);} Object value = getValue (key) If ((value! = null) & & log.isTraceEnabled ()) {String msg = "Retrieved value of type [" + value.getClass (). GetName () + "] for key [" + key + "]" + "bound to thread [" + Thread.currentThread (). GetName () + "]"; log.trace (msg);} return value } private static Object getValue (Object key) {Map perThreadResources = resources.get (); return perThreadResources! = null? PerThreadResources.get (key): null;}}

There is a LocalThread object in the ThreadContext, which shows that the Subject is bound to the current thread.

Public interface Subject {public static class Builder {private final SubjectContext subjectContext; private final SecurityManager securityManager; public Builder () {this (SecurityUtils.getSecurityManager ());} public Builder (SecurityManager securityManager) {if (securityManager = = null) {throw new NullPointerException ("SecurityManager method argument cannot be null.");} this.securityManager = securityManager This.subjectContext = newSubjectContextInstance (); if (this.subjectContext = = null) {throw new IllegalStateException ("Subject instance returned from 'newSubjectContextInstance'" + "cannot be null.");} this.subjectContext.setSecurityManager (securityManager) } protected SubjectContext newSubjectContextInstance () {return new DefaultSubjectContext ();} public Subject buildSubject () {return this.securityManager.createSubject (this.subjectContext);}

At this point, when Builder creates the Subject, it is delegated to SecurityManager, and the SecurityManager is returned from the SecurityUtils. Then you have to trace back to how SecurityManager was created to learn more about the creation of Subject. According to the inheritance diagram of Subject, it is only an interface, so which one should its implementation class correspond to, and how to determine which one should be used?

When integrating shrio in a web environment, the following configuration is generally added to the web.xml file

Org.apache.shiro.web.env.EnvironmentLoaderListener ShiroFilter org.apache.shiro.web.servlet.ShiroFilter ShiroFilter / * REQUEST FORWARD INCLUDE ERROR

Since the Subject is obtained and used during the request, let's take a look at what the ShiroFilter class contains. First, look at the inheritance relationship of ShiroFilter.

Public class ShiroFilter extends AbstractShiroFilter {@ Override public void init () throws Exception {WebEnvironment env = WebUtils.getRequiredWebEnvironment (getServletContext ()); setSecurityManager (env.getWebSecurityManager ()); FilterChainResolver resolver = env.getFilterChainResolver (); if (resolver! = null) {setFilterChainResolver (resolver);}

We see the init method here, and see that the name is supposed to be initialized to run when Filter, so where is it called? let's continue to look at its parent class.

Public abstract class AbstractFilter extends ServletContextSupport implements Filter {public final void init (FilterConfig filterConfig) throws ServletException {setFilterConfig (filterConfig); try {onFilterConfigSet ();} catch (Exception e) {if (e instanceof ServletException) {throw (ServletException) e } else {if (log.isErrorEnabled ()) {log.error ("Unable to start Filter: [" + e.getMessage () + "].", e);} throw new ServletException (e) } public abstract class AbstractShiroFilter extends OncePerRequestFilter {protected final void onFilterConfigSet () throws Exception {/ / added in 1.2 for SHIRO-287: applyStaticSecurityManagerEnabledConfig (); init (); / / called the init () method of the subclass [ShiroFilter] (starting to get objects such as WebEnvironment) ensureSecurityManager () / / confirm whether SecurityManager exists. If it does not exist, create a default DefaultWebSecurityManager object / / added in 1.2 for SHIRO-287: if (isStaticSecurityManagerEnabled ()) {/ * Note: it is important here that it is not recommended to save SecurityManager objects in static variables in WEB environments. Determine whether to save SecurityManager through SecurityUtils as a static variable according to the initialization parameters configured by Filter * / SecurityUtils.setSecurityManager (getSecurityManager ());}

You can see that AbstractFilter calls AbstractShiroFilter, and then calls the init method of ShiroFilter. The purpose of the init method is to get the WebEnvironment object, and the code in its WebUtils is simple, that is, to get the WebEnvironment object directly from the ServletContext, and if it is empty, an exception is thrown.

Public class WebUtils {public static WebEnvironment getRequiredWebEnvironment (ServletContext sc) throws IllegalStateException {WebEnvironment we = getWebEnvironment (sc); if (we = = null) {throw new IllegalStateException ("No WebEnvironment found: no EnvironmentLoaderListener registered?");} return we;} public static WebEnvironment getWebEnvironment (ServletContext sc) {return getWebEnvironment (sc, EnvironmentLoader.ENVIRONMENT_ATTRIBUTE_KEY) } public static WebEnvironment getWebEnvironment (ServletContext sc, String attrName) {if (sc = = null) {throw new IllegalArgumentException ("ServletContext argument must not be null.");} Object attr = sc.getAttribute (attrName); if (attr = = null) {return null;} if (attr instanceof RuntimeException) {throw (RuntimeException) attr } if (attr instanceof Error) {throw (Error) attr;} if (attr instanceof Exception) {throw new IllegalStateException ((Exception) attr);} if (! (attr instanceof WebEnvironment)) {throw new IllegalStateException ("Context attribute is not of type WebEnvironment:" + attr);} return (WebEnvironment) attr;}

Then let's take a look at the definition of WebEnvironment:

Public interface Environment {/ * * Returns the application's {@ code SecurityManager} instance. * * @ return the application's {@ code SecurityManager} instance. * / SecurityManager getSecurityManager ();} public interface WebEnvironment extends Environment {/ * Returns the web application's {@ code FilterChainResolver} if one has been configured or {@ code null} if one * is not available. * * @ return the web application's {@ code FilterChainResolver} if one has been configured or {@ code null} if one * is not available. * / FilterChainResolver getFilterChainResolver (); / * Returns the {@ code ServletContext} associated with this {@ code WebEnvironment} instance. A web application * typically only has a single {@ code WebEnvironment} associated with its {@ code ServletContext}. * * @ return the {@ code ServletContext} associated with this {@ code WebEnvironment} instance. * / ServletContext getServletContext (); / * * Returns the web application's security manager instance. * * @ return the web application's security manager instance. * / WebSecurityManager getWebSecurityManager ();}

Globally unique SecurityManager objects are directly saved in WebEnvironment. Next we need to track the creation of the SecurityManager object. We have to go back to the following objects.

Org.apache.shiro.web.env.EnvironmentLoaderListenerpublic 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 static final String ENVIRONMENT_ATTRIBUTE_KEY = EnvironmentLoader.class.getName () + ".ENVIRONMENT _ ATTRIBUTE_KEY" 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 = 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; environment.setServletContext (sc); if (configSpecified & & (environment instanceof ResourceConfigurable)) {((ResourceConfigurable) environment) .setConfigLocations (configLocations);} customizeEnvironment (environment) LifecycleUtils.init (environment); / / Note: the init method of environment will be called to initialize environment return environment;} protected WebEnvironment determineWebEnvironment (ServletContext servletContext) {Class.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report