Shiro User Manual-Custom Subjects

1. Custom Subject Instances
Shiro在1.0版本添加了一个新的特性,用于在特殊情景自定义subject。

2. Subject.Builder
Subject.Builder可以创建一个匿名,无session关联的Subject实例:
Subject subject = new Subject.Builder().buildSubject()

默认无参的Subject.Builder将使用应用中存在的SecurityManager。也可以指定 SecurityManager:
SecurityManager securityManager = //acquired from somewhere
Subject subject = new Subject.Builder(securityManager).buildSubject();

Subject.Builder提供的其他方法都需要在buildSubject方法之前调用,假设有一个session ID,你想设置到Subject的session上:
Serializable sessionId = //acquired from somewhere
Subject subject = new Subject.Builder().sessionId(sessionId).buildSubject();

或者想设置Subject的标识信息:
Object userIdentity = //a long ID or String username, or whatever the "myRealm" requires
String realmName = "myRealm";
PrincipalCollection principals = new SimplePrincipalCollection(userIdentity, realmName);
Subject subject = new Subject.Builder().principals(principals).buildSubject();

然后就可以使用Subject。需要注意的是,这样方式创建的Subject不会自动与应用线程绑定。如果想随处调用SecurityUtils.getSubject(),必须保证Subject与线程已绑定。

3. Thread Association(线程关联)
与线程绑定有三种方式:
  1. Automatic Association -- 通过Subject.execute方法执行Callable或Runnable。
  2. Manual Association  -- 手动绑定或解除。
  3. Different Thread  -- 通过Subject.associateWith方法将Subject与Callable或Runnable绑定,并使用其他线程执行Callable或Runnable。

3.1 Automatic Association(自动关联)
  如果想让Subject与线程暂时性绑定,可以直接通过Subject的execute方法执行Callable或Runnable,线程执行完毕,就解除绑定。
  假如在应用启动时,有一些操作需要执行,当执行完后,希望Subject可以回到自动绑定到线程的环境下,可以这样做:
Subject subject = //build or acquire subject
subject.execute( new Runnable() {
    public void run() {
        //subject is 'bound' to the current thread now
        //any SecurityUtils.getSubject() calls in any
        //code called from here will work
    }
});
//At this point, the Subject is no longer associated
//with the current thread and everything is as it was before

也支持Callable:
Subject subject = //build or acquire subject
MyResult result = subject.execute( new Callable<MyResult>() {
    public MyResult call() throws Exception {
        //subject is 'bound' to the current thread now
        //any SecurityUtils.getSubject() calls in any
        //code called from here will work
        ...
        //finish logic as this Subject
        ...
        return myResult;        
    }
});
//At this point, the Subject is no longer associated
//with the current thread and everything is as it was before

这在框架开发中很有用。比如,Shiro支持Spring的远程调用,这可以保证远程调用被执行:
Subject.Builder builder = new Subject.Builder();
//populate the builder's attributes based on the incoming RemoteInvocation
...
Subject subject = builder.buildSubject();

return subject.execute(new Callable() {
    public Object call() throws Exception {
        return invoke(invocation, targetObject);
    }
});


3.2 Manual Association(手动关联)
在某些场景下,比如说使用Shiro进行框架级的集成开发时,就可能需要手动管理ThreadState(Shiro中保证Subject可以在线程执行间随处可用)。需要注意的是,要保证线程执行完后,清除ThreadState:
Subject subject = new Subject.Builder()...
ThreadState threadState = new SubjectThreadState(subject);
threadState.bind();
try {
    //execute work as the built Subject
} finally {
    //ensure any state is cleaned so the thread won't be 
    //corrupt in a reusable or pooled thread environment
    threadState.clear();
}


3.3 A Different Thread(使用其他线程方式)
Subject.associateWith方法将Subject与Callable或Runnable绑定,在线程执行期间,Subject被挂起,直到线程执行完后,Subject才可用, Callable例子:
Subject subject = new Subject.Builder()...
Callable work = //build/acquire a Callable instance.
//associate the work with the built subject so SecurityUtils.getSubject() calls works properly:
work = subject.associateWith(work);
ExecutorService executorService = new java.util.concurrent.Executors.newCachedThreadPool();
//execute the work on a different thread as the built Subject:
executor.execute(work);

使用Runnable的例子:
Subject subject = new Subject.Builder()...
Runnable work = //build/acquire a Runnable instance.
//associate the work with the built subject so SecurityUtils.getSubject() calls works properly:
work = subject.associateWith(work);
Executor executor = new java.util.concurrent.Executors.newCachedThreadPool();
//execute the work on a different thread as the built Subject:
executor.execute(work);

猜你喜欢

转载自technoboy.iteye.com/blog/1848403