1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 module hunt.shiro.subject.support.SubjectThreadState; 20 21 import hunt.shiro.subject.support.DelegatingSubject; 22 import hunt.shiro.subject.support.SubjectThreadState; 23 24 import hunt.shiro.mgt.SecurityManager; 25 import hunt.shiro.subject.Subject; 26 import hunt.shiro.util.CollectionUtils; 27 import hunt.shiro.util.ThreadContext; 28 import hunt.shiro.util.ThreadState; 29 30 import hunt.collection.Map; 31 import hunt.Exceptions; 32 33 /** 34 * Manages thread-state for {@link Subject Subject} access (supporting 35 * {@code SecurityUtils.}{@link hunt.shiro.SecurityUtils#getSubject() getSubject()} calls) 36 * during a thread's execution. 37 * <p/> 38 * The {@link #bind bind} method will bind a {@link Subject} and a 39 * {@link hunt.shiro.mgt.SecurityManager SecurityManager} to the {@link ThreadContext} so they can be retrieved 40 * from the {@code ThreadContext} later by any 41 * {@code SecurityUtils.}{@link hunt.shiro.SecurityUtils#getSubject() getSubject()} calls that might occur during 42 * the thread's execution. 43 * 44 */ 45 class SubjectThreadState : ThreadState { 46 47 private Map!(string, Object) originalResources; 48 49 private Subject subject; 50 private SecurityManager securityManager; 51 52 /** 53 * Creates a new {@code SubjectThreadState} that will bind and unbind the specified {@code Subject} to the 54 * thread 55 * 56 * @param subject the {@code Subject} instance to bind and unbind from the {@link ThreadContext}. 57 */ 58 this(Subject subject) { 59 if (subject is null) { 60 throw new IllegalArgumentException("Subject argument cannot be null."); 61 } 62 this.subject = subject; 63 64 SecurityManager securityManager = null; 65 DelegatingSubject ds = cast(DelegatingSubject)subject; 66 if (ds !is null) { 67 securityManager = ds.getSecurityManager(); 68 } 69 if ( securityManager is null) { 70 securityManager = ThreadContext.getSecurityManager(); 71 } 72 this.securityManager = securityManager; 73 } 74 75 /** 76 * Returns the {@code Subject} instance managed by this {@code ThreadState} implementation. 77 * 78 * @return the {@code Subject} instance managed by this {@code ThreadState} implementation. 79 */ 80 protected Subject getSubject() { 81 return this.subject; 82 } 83 84 /** 85 * Binds a {@link Subject} and {@link hunt.shiro.mgt.SecurityManager SecurityManager} to the 86 * {@link ThreadContext} so they can be retrieved later by any 87 * {@code SecurityUtils.}{@link hunt.shiro.SecurityUtils#getSubject() getSubject()} calls that might occur 88 * during the thread's execution. 89 * <p/> 90 * Prior to binding, the {@code ThreadContext}'s existing {@link ThreadContext#getResources() resources} are 91 * retained so they can be restored later via the {@link #restore restore} call. 92 */ 93 void bind() { 94 SecurityManager securityManager = this.securityManager; 95 if ( securityManager is null ) { 96 //try just in case the constructor didn't find one at the time: 97 securityManager = ThreadContext.getSecurityManager(); 98 } 99 this.originalResources = ThreadContext.getResources(); 100 ThreadContext.remove(); 101 102 ThreadContext.bind(this.subject); 103 if (securityManager !is null) { 104 ThreadContext.bind(securityManager); 105 } 106 } 107 108 /** 109 * {@link ThreadContext#remove Remove}s all thread-state that was bound by this instance. If any previous 110 * thread-bound resources existed prior to the {@link #bind bind} call, they are restored back to the 111 * {@code ThreadContext} to ensure the thread state is exactly as it was before binding. 112 */ 113 void restore() { 114 ThreadContext.remove(); 115 if (!CollectionUtils.isEmpty(this.originalResources)) { 116 ThreadContext.setResources(this.originalResources); 117 } 118 } 119 120 /** 121 * Completely {@link ThreadContext#remove removes} the {@code ThreadContext} state. Typically this method should 122 * only be called in special cases - it is more 'correct' to {@link #restore restore} a thread to its previous 123 * state than to clear it entirely. 124 */ 125 void clear() { 126 ThreadContext.remove(); 127 } 128 }