SecurityUtils.getSubject()
1 | // line 38 |
2 | /** |
3 | * Returns the currently accessible {@code Subject} available to the calling code depending on |
4 | * runtime environment. |
5 | * <p/> |
6 | * This method is provided as a way of obtaining a {@code Subject} without having to resort to |
7 | * implementation-specific methods. It also allows the Shiro team to change the underlying implementation of |
8 | * this method in the future depending on requirements/updates without affecting your code that uses it. |
9 | * |
10 | * @return the currently accessible {@code Subject} accessible to the calling code. |
11 | * @throws IllegalStateException if no {@link Subject Subject} instance or |
12 | * {@link SecurityManager SecurityManager} instance is available with which to obtain |
13 | * a {@code Subject}, which which is considered an invalid application configuration |
14 | * - a Subject should <em>always</em> be available to the caller. |
15 | */ |
16 | public static Subject getSubject() { |
17 | Subject subject = ThreadContext.getSubject(); |
18 | if (subject == null) { |
19 | subject = (new Subject.Builder()).buildSubject(); |
20 | ThreadContext.bind(subject); |
21 | } |
22 | return subject; |
23 | } |
ThreadContext.getSubject()
从线程局部变量 ThreadLocal<Map<String, Object>> resource 里,获取 key 为
ThreadContext.class.getName() + "_SUBJECT_KEY"的 Subject 对象
1 | /** |
2 | * Convenience method that simplifies retrieval of a thread-bound Subject. If there is no |
3 | * Subject bound to the thread, this method returns <tt>null</tt>. It is merely a convenient wrapper |
4 | * for the following: |
5 | * <p/> |
6 | * <code>return (Subject)get( SUBJECT_KEY );</code> |
7 | * <p/> |
8 | * This method only returns the bound value if it exists - it does not remove it |
9 | * from the thread. To remove it, one must call {@link #unbindSubject() unbindSubject()} instead. |
10 | * |
11 | * @return the Subject object bound to the thread, or <tt>null</tt> if there isn't one bound. |
12 | * @since 0.2 |
13 | */ |
14 | public static Subject getSubject() { |
15 | // public static final String SUBJECT_KEY = ThreadContext.class.getName() + "_SUBJECT_KEY"; |
16 | return (Subject) get(SUBJECT_KEY); |
17 | } |
18 | |
19 | |
20 | /** |
21 | * Returns the object for the specified <code>key</code> that is bound to |
22 | * the current thread. |
23 | * |
24 | * @param key the key that identifies the value to return |
25 | * @return the object keyed by <code>key</code> or <code>null</code> if |
26 | * no value exists for the specified <code>key</code> |
27 | */ |
28 | public static Object get(Object key) { |
29 | if (log.isTraceEnabled()) { |
30 | String msg = "get() - in thread [" + Thread.currentThread().getName() + "]"; |
31 | log.trace(msg); |
32 | } |
33 | |
34 | Object value = getValue(key); |
35 | if ((value != null) && log.isTraceEnabled()) { |
36 | String msg = "Retrieved value of type [" + value.getClass().getName() + "] for key [" + |
37 | key + "] " + "bound to thread [" + Thread.currentThread().getName() + "]"; |
38 | log.trace(msg); |
39 | } |
40 | return value; |
41 | } |
42 | |
43 | |
44 | /** |
45 | * Returns the value bound in the {@code ThreadContext} under the specified {@code key}, or {@code null} if there |
46 | * is no value for that {@code key}. |
47 | * |
48 | * @param key the map key to use to lookup the value |
49 | * @return the value bound in the {@code ThreadContext} under the specified {@code key}, or {@code null} if there |
50 | * is no value for that {@code key}. |
51 | * @since 1.0 |
52 | */ |
53 | private static Object getValue(Object key) { |
54 | // private static final ThreadLocal<Map<Object, Object>> resources = new InheritableThreadLocalMap<Map<Object, Object>>(); |
55 | Map<Object, Object> perThreadResources = resources.get(); |
56 | return perThreadResources != null ? perThreadResources.get(key) : null; |
57 | } |
(new Subject.Builder()).buildSubject()
(new Subject.Builder())
这里暂时不去穷究 SecurityUtils.getSecurityManager()
1 | /** |
2 | * Constructs a new {@link Subject.Builder} instance, using the {@code SecurityManager} instance available |
3 | * to the calling code as determined by a call to {@link org.apache.shiro.SecurityUtils#getSecurityManager()} |
4 | * to build the {@code Subject} instance. |
5 | */ |
6 | public Builder() { |
7 | this(SecurityUtils.getSecurityManager()); |
8 | } |
9 | |
10 | /** |
11 | * Constructs a new {@link Subject.Builder} instance which will use the specified {@code SecurityManager} when |
12 | * building the {@code Subject} instance. |
13 | * |
14 | * @param securityManager the {@code SecurityManager} to use when building the {@code Subject} instance. |
15 | */ |
16 | public Builder(SecurityManager securityManager) { |
17 | if (securityManager == null) { |
18 | throw new NullPointerException("SecurityManager method argument cannot be null."); |
19 | } |
20 | this.securityManager = securityManager; |
21 | this.subjectContext = newSubjectContextInstance(); |
22 | if (this.subjectContext == null) { |
23 | throw new IllegalStateException("Subject instance returned from 'newSubjectContextInstance' " + |
24 | "cannot be null."); |
25 | } |
26 | this.subjectContext.setSecurityManager(securityManager); |
27 | } |
(new Subject.Builder()).buildSubject()
1 | /** |
2 | * Creates and returns a new {@code Subject} instance reflecting the cumulative state acquired by the |
3 | * other methods in this class. |
4 | * <p/> |
5 | * This {@code Builder} instance will still retain the underlying state after this method is called - it |
6 | * will not clear it; repeated calls to this method will return multiple {@link Subject} instances, all |
7 | * reflecting the exact same state. If a new (different) {@code Subject} is to be constructed, a new |
8 | * {@code Builder} instance must be created. |
9 | * <p/> |
10 | * <b>Note</b> that the returned {@code Subject} instance is <b>not</b> automatically bound to the application |
11 | * (thread) for further use. That is, |
12 | * {@link org.apache.shiro.SecurityUtils SecurityUtils}.{@link org.apache.shiro.SecurityUtils#getSubject() getSubject()} |
13 | * will not automatically return the same instance as what is returned by the builder. It is up to the |
14 | * framework developer to bind the returned {@code Subject} for continued use if desired. |
15 | * |
16 | * @return a new {@code Subject} instance reflecting the cumulative state acquired by the |
17 | * other methods in this class. |
18 | */ |
19 | public Subject buildSubject() { |
20 | return this.securityManager.createSubject(this.subjectContext); |
21 | } |
22 | |
23 | // 在构造函数中 `this.subjectContext = newSubjectContextInstance();` |
24 | /** |
25 | * Creates a new {@code SubjectContext} instance to be used to populate with subject contextual data that |
26 | * will then be sent to the {@code SecurityManager} to create a new {@code Subject} instance. |
27 | * |
28 | * @return a new {@code SubjectContext} instance |
29 | */ |
30 | protected SubjectContext newSubjectContextInstance() { |
31 | return new DefaultSubjectContext(); |
32 | } |
ThreadContext.bind(subject);
把 subject 绑定到线程内部
1 | /** |
2 | * Convenience method that simplifies binding a Subject to the ThreadContext. |
3 | * <p/> |
4 | * <p>The method's existence is to help reduce casting in your own code and to simplify remembering of |
5 | * ThreadContext key names. The implementation is simple in that, if the Subject is not <tt>null</tt>, |
6 | * it binds it to the thread, i.e.: |
7 | * <p/> |
8 | * <pre> |
9 | * if (subject != null) { |
10 | * put( SUBJECT_KEY, subject ); |
11 | * }</pre> |
12 | * |
13 | * @param subject the Subject object to bind to the thread. If the argument is null, nothing will be done. |
14 | * @since 0.2 |
15 | */ |
16 | public static void bind(Subject subject) { |
17 | if (subject != null) { |
18 | put(SUBJECT_KEY, subject); |
19 | } |
20 | } |
小结
SecurityUtils.getSubject() 先ThreadContext.getSubject() 来获取subject;如果为null,则调用 (new Subject.Builder()).buildSubject() 来创建subject,在该方法内部最终调用 SecurityManager.createSubject(subjectContext)