Apache Shiro Integrated Redis Cache

Source: Internet
Author: User
Tags auth bind hash int size json redis log4j

Shiro is often used in the project to do permission authentication and authorization functions, when the user authentication is successful, the first time to access a restricted resource, Shiro will load all the user access to the identity of the permission. By default, Shiro does not cache these permission identities. When you access a restricted resource again, you also load the identity of the permission that the user can access.
This process is obviously not suitable for production environments when the request is too long, so you need to cache the Shiro. The Shiro itself has a built-in cache feature that needs to be configured to enable it. Shiro provides us with two cache implementations, One is based on local memory (Org.apache.shiro.cache.MemoryConstrainedCacheManager) and the other is based on Ehcache (Org.apache.shiro.cache.ehcache.EhCacheManag ER). These two sets of implementations are only suitable for single-player play, when in the distributed environment, the effect is not ideal. A set of Shiro cache implementations based on Redis was developed.
The following does not describe the integration of spring and Shiro, such articles on the Internet, which is not the focus of this article, so the reader needs to have the spring and Shiro integration, and then the practice of this article. Also does not describe the integration of spring and Jedis, please configure the Spring and Jedis framework, and configure the Redistemplate bean as well.

First write the following two classes to configure these two classes in the Shiro configuration file.
Because it is directly from the company's project to copy the source code, so the package name has been replaced, readers should adjust the limitations according to the actual situation.

Certification and authorization class package Com.xxx.common.shiro;

Import java.util.List;
Import Org.apache.logging.log4j.LogManager;
Import Org.apache.logging.log4j.Logger;
Import org.apache.shiro.authc.AuthenticationException;
Import Org.apache.shiro.authc.AuthenticationInfo;
Import Org.apache.shiro.authc.AuthenticationToken;
Import Org.apache.shiro.authc.SimpleAuthenticationInfo;
Import Org.apache.shiro.authc.UsernamePasswordToken;
Import Org.apache.shiro.authz.AuthorizationInfo;
Import Org.apache.shiro.authz.SimpleAuthorizationInfo;
Import Org.apache.shiro.cache.Cache;
Import Org.apache.shiro.realm.AuthorizingRealm;
Import org.apache.shiro.subject.PrincipalCollection;
Import org.springframework.beans.factory.annotation.Autowired;

Import org.springframework.stereotype.Component;
Import com.xxx.common.exception.ReadMessageException;
Import Com.xxx.api.AuthorityApi;
Import Com.xxx.api.RoleApi;
Import Com.xxx.api.UserApi;
Import com.xxx.domain.Authority;
Import Com.xxx.domain.Role;
Import Com.xxx.domain.User;
@Component public class Basicauthorizingrealm extends Authorizingrealm {private static final Logger Logger=logmanag

    Er.getlogger (Basicauthorizingrealm.class);
    @Autowired private Userapi Userapi;
    @Autowired private Roleapi Roleapi;

    @Autowired private Authorityapi Authorityapi;

    private static final String authorization_cache_name= "AUTHORIZATION";
    Public Basicauthorizingrealm () {super.setauthorizationcachename (authorization_cache_name); }/*** * Obtain authentication information */@Override protected authenticationinfo dogetauthenticationinfo (Authenticationtok

        En at) throws authenticationexception {Usernamepasswordtoken token = (usernamepasswordtoken) at;
            try {User user = Userapi.getbyusername (token.getusername ());
            if (user==null) {throw new Authenticationexception ("Username or password error");
            } string Pwd=new string (Token.getpassword ()); if (!userapi.checkpassword (user.getId (), pwd) {throw new Authenticationexception ("Username or password error");
            } if (User.getstatus () ==user.status_disabled) {throw new Authenticationexception ("User has been disabled"); Clearauthorizationinfocache (user);//After the user logs on, clear the user cache to reload the user rights return new Simpleauthent
        Icationinfo (User, Token.getpassword (), GetName ());
            } catch (Readmessageexception e) {logger.error (e);
        throw new Authenticationexception (e);
            } catch (Authenticationexception e) {logger.error (e);
        Throw e; }}/*** * Get authorization information */@Override protected authorizationinfo dogetauthorizationinfo (principalcoll
        Ection pc) {User user = (user) Pc.fromrealm (getName ()). Iterator (). Next ();

        Simpleauthorizationinfo info = new Simpleauthorizationinfo ();

            try {list<role> roles=roleapi.queryroles (User.getid ()); for (Role role:roles) {Info.addrole (Role.getcode ());
                List<authority> auths=authorityapi.queryauths (Role.getid ());
                    for (authority auth:auths) {if (auth.getpermission () ==null) break; String[] Perms=auth.getpermission (). Split (",");
                    Supports comma-separated permissions to identify for (String perm:perms) {info.addstringpermission (perm);
        }}}} catch (Readmessageexception e) {logger.error (e);
    } return info; /** * Clears the cache for all users */public void Clearauthorizationinfocache () {cache<object, Authorization
        info> cache = Getauthorizationcache ();
        if (cache!=null) {cache.clear ();
        }}/** * Clears the cache for the specified user * @param user */private void Clearauthorizationinfocache (user user) { Cache<object, authorizationinfo> cache = Getauthorizationcache();
    Cache.remove (User.getid ());
 }
}
Redis Cache implementation class package Com.xxx.common.shiro;
Import java.util.Collection;

Import Java.util.Set;
Import Org.apache.shiro.cache.Cache;
Import org.apache.shiro.cache.CacheException;
Import Org.apache.shiro.cache.CacheManager;
Import org.apache.shiro.subject.PrincipalCollection;
Import org.springframework.beans.factory.annotation.Autowired;
Import org.springframework.data.redis.core.BoundHashOperations;
Import Org.springframework.data.redis.core.RedisTemplate;

Import org.springframework.stereotype.Component;

Import Com.xxx.domain.User;

    @Component public class Rediscachemanager implements CacheManager {private String Cachekeyprefix = "Shiro:";

    @Autowired private redistemplate<string, object> redistemplate; @Override public <k, v> cache<k, v> getcache (String name) throws Cacheexception {return new Shiro
    Rediscache<k,v> (Cachekeyprefix+name); }/** * A redis cache tailored for Shiro, special optimizations for authorization cache */public classShirorediscache<k, V> implements Cache<k, v> {private String CacheKey;
        Public Shirorediscache (String cacheKey) {this.cachekey=cachekey;  } @Override public V get (K key) throws Cacheexception {boundhashoperations<string,k,v>
            hash = Redistemplate.boundhashops (CacheKey);
            Object K=hashkey (key);
        Return Hash.get (k); } @Override Public V put (K key, V value) throws Cacheexception {Boundhashoperations<strin
            g,k,v> hash = redistemplate.boundhashops (CacheKey);
            Object K=hashkey (key);
            Hash.put ((k) K, value);
        return value; } @Override Public V remove (K key) throws Cacheexception {boundhashoperations<string,k,v& Gt

            hash = Redistemplate.boundhashops (CacheKey);
            Object K=hashkey (key);
            V Value=hash.get (k);
            Hash.delete (k); Return VAlue;
        } @Override public void Clear () throws Cacheexception {Redistemplate.delete (CacheKey); } @Override public int size () {boundhashoperations<string,k,v> hash = Redistemplat
            E.boundhashops (CacheKey);
        Return Hash.size (). Intvalue (); } @Override public set<k> keys () {boundhashoperations<string,k,v> hash = Rediste
            Mplate.boundhashops (CacheKey);
        return Hash.keys (); } @Override public collection<v> values () {boundhashoperations<string,k,v> hash
            = Redistemplate.boundhashops (CacheKey);
        return Hash.values (); } protected Object HashKey (K key) {if (key instanceof PrincipalCollection) {///Here is important, if key is login credentials, then this is a visit Ask the user's authorization cache, convert the login credentials to the user object, return the user's id attribute as a hash key, or the user object as a hash key, so it is not good to clear the cache of the specified user PrincipalCollection pc= ( PrincipalCollection) key;
                User user = (user) pc.getprimaryprincipal ();
            return User.getid ();
        } return key;
 }
    }

}

Configure the above two class objects in the Shiro configuration file

    <!--definition Shiro Security Management configuration--
    <bean id= "SecurityManager" class= " Org.apache.shiro.web.mgt.DefaultWebSecurityManager ">
        <property name=" Realm "ref=" Basicauthorizingrealm "/>
        <property name=" CacheManager "ref=" Rediscachemanager "/>
    </bean>

At this point, the integration is complete, the following is my login interface and the logoff interface controller code for reference.

Package Com.xxx.controller.sys;
Import Org.apache.shiro.SecurityUtils;
Import Org.apache.shiro.authc.UsernamePasswordToken;
Import Org.apache.shiro.subject.Subject;
Import Org.springframework.web.bind.annotation.RequestBody;
Import org.springframework.web.bind.annotation.RequestMapping;
Import Org.springframework.web.bind.annotation.RequestMethod;

Import Org.springframework.web.bind.annotation.RestController;

Import Com.alibaba.fastjson.JSONObject;

Import Com.xxx.common.JsonMessage;
     @RestController @RequestMapping ("/api/sys") public class Logincontroller extends Basecontroller {/** * login user * @param JSON * @return */@RequestMapping (value = "/login", method = requestmethod.post) public jsonm
        Essage Login (@RequestBody jsonobject json) {String username = json.getstring ("username");

        String Password = json.getstring ("password");
        Subject Subject = Securityutils.getsubject (); if (subject.isauthenticated ()) {REturn Respok ();
        } Usernamepasswordtoken token = new Usernamepasswordtoken (username, password);
        Token.setrememberme (TRUE);
        Subject.login (token);
    return Respok (); /** * Log Off user * @return */@RequestMapping (value = "/logout", method={requestmethod.post}) publi
        C Jsonmessage Logout () {Subject Subject = Securityutils.getsubject ();
        if (subject.isauthenticated ()) {subject.logout ();
    } return Respok ();
 }

}

Code is more, need to have shiro,redis,spring MVC Foundation to understand, forgive me.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.