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.