Java EE – inject CDI managed beans into custom Shiro authorizationrealm

In the application I'm building, we use direct Java 6 EE and JBoss (without spring, etc.), JPA / Hibernate, JSF, CDI and EJB

I didn't find many good general security solutions (the suggestions are welcome), but I found the best one is Apache Shiro

However, this seems to have some disadvantages Some of these can be read on balus C's website:

http://balusc.blogspot.com/2013/01/apache-shiro-is-it-ready-for-java-ee-6.html

But I have stumbled upon another big problem, which has been mentioned here about dependency injection and proxy

Basically, I have a good JPA based userdao that provides everything needed for authentication My database is in persistence XML and mydatabase DS XML (for JBoss)

It seems foolish to copy all this configuration information again and add the user table query to Shiro Ini So that's why I chose to write my own realm instead of using jdbcrealm

My first attempt was to authorize the authorizationrealm... Similar to:

@Stateless
public MyAppRealm extends AuthorizingRealm {
    @Inject private UserAccess userAccess;

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
        AuthenticationToken token) throws AuthenticationException {

        UsernamePasswordToken userPassToken = (UsernamePasswordToken) token;

        User user = userAccess.getUserByEmail(userPassToken.getUsername());
        if (user == null) {
            return null;
        }

        AuthenticationInfo info = new SimpleAuthenticationInfo();
        // set data in AuthenticationInfo based on data from the user object

        return info;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // TODO
        return null;
    }
}

This is not good because myappream cannot be proxied because there is a final init () method in the parent class

My second attempt is to make myappream implement all required interfaces and delegate them to the instance of authoringrealm I don't like this, but I can try it

This allows me to go further, webapp starts, but it's still not enough The reason is in the configuration file Shiro Ini, I specify the class of my domain:

myAppRealm = com.myapp.MyAppRealm

This almost tells me that Shiro will be responsible for creating myappream instances Therefore, it will not be managed by CDI, so it will not be injected, which is what I see

I've seen this so answer, but I can't see how it might work, because a subclass of authorizingrealm will inherit a final init () method, which means that the subclass can't be proxied

Do you have any ideas to solve this problem?

Solution

This is a classic problem: you have two different frameworks that both manage the object life cycle and interact with them, but both must adhere to complete control (my spiritual image is like the battle between Godzilla and Goda in central Tokyo) You may not immediately see Shiro as a competitor of CDI, but because it creates instances of its objects, it basically contains a small and basic dependency injection framework (perhaps this is a di version of Greenspun's ten rule) I encountered a similar problem, which caused the web framework to create and inject instances of its supporting beans to interact with CDI

The solution to this problem is to create a clear bridge between the two frameworks If you are really lucky, the non CDI framework will have hooks to allow you to customize object creation, in which you can insert content using CDI (for example, in the strips web framework, you can write an actionresolver using CDI)

If not, the bridge must take the form of an agent In this agent, you can perform explicit CDI lookup You can boot into CDI by grasping the beanmanager, which allows you to set the context and then create beans in it Such a thing

BeanManager beanManager = (BeanManager) new InitialContext().lookup("java:comp/BeanManager");
Bean<UserDAO> userDAObean = (Bean<UserDAO>) beanManager.resolve(beanManager.getBeans(UserDAO.class));
CreationalContext<?> creationalContext = beanManager.createCreationalContext(null);
UserDAO userDAO = userDAObean.create(creationalContext);

Userdao is an injected CDI managed bean bound to the context you now own as creationalcontext

When you complete the bean (you can do the query by yourself, once per request or once per application life cycle), you can release the bean:

creationalContext.release();
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>