Permission module design, permission Module

Source: Internet
Author: User

Permission module design, permission Module

The shiro framework is used in the permission management module of the management background.

Shiro has the following advantages: shiro is relatively lightweight compared with Spring Security, has a high degree of freedom to use, and has a mature combination with the Spring framework. The disadvantage is that shiro does not implement caching, so you need to define the caching implementation by yourself. The update is slow, and some functions need to be expanded by yourself.

Shiro documentation: http://shiro.apache.org/static/1.2.3/apidocs/

Getting Started: http://shiro.apache.org/10-minute-tutorial.html

The following summarizes how to use shiro in the project and how to expand shiro in the management background project.

 

1. Use shiro to manage permissions

1. Introduce the packages required by shiro. In a maven project, add the following dependency to pom. xml:

<! -- Shiro permission management --> <dependency> <groupId> org. apache. shiro </groupId> <artifactId> shiro-core </artifactId> <version> 1.1.0 </version> </dependency> <groupId> org. apache. shiro </groupId> <artifactId> shiro-web </artifactId> <version> 1.1.0 </version> </dependency> <groupId> org. apache. shiro </groupId> <artifactId> shiro-spring </artifactId> <version> 1.1.0 </version> </dependency> <! -- Shiro permission management end -->

2. Add the shiro configuration in the project.

Create a spring-shiro.xml under the spring configuration file directory. The content is as follows:

<! -- Shiro permission management configuration --> <bean id = "shiroFilter" class = "org. apache. shiro. spring. web. ShiroFilterFactoryBean"> <! -- Shiro uses a filter to control permissions --> <property name = "securityManager" ref = "securityManager"/> <property name = "loginUrl" value = "/login/execute. do "/> <! -- Logon page --> <property name = "successUrl" value = "/index. jsp"/> <! -- The page to jump to after successful login --> <property name = "unauthorizedUrl" value = "/login/execute. do"/> <! -- When a user requests a resource that has no permission, the user jumps to this url --> <property name = "filters"> <util: map> <entry key = "authc"> <bean class = "org. apache. shiro. web. filter. authc. passThruAuthenticationFilter "/> </entry> </util: map> </property> <property name =" filterChainDefinitions "> <! -- Configure the permissions required by the user to access url resources. Configure the priority from top to bottom --> <value>/= anon/template/main. jsp = user <! -- Api user information -->/api/createApiUser ** = perms [api: user: create] <! -- The permission can be classified by ":". If you have the api permission, it is equivalent to having the api * permission (the parent permission covers the sub-permission) -->/api/updateApiUser ** = perms [api: user: update]/api/* User * = perms [api: user: view]/template/apiUserManage/** = perms [api: user: view] <! -- Api Interface Management -->/api/* interface * = perms [api: user: Interface] <! -- Api statistics -->/api/querySummaryData ** = perms [api: data]/template/apiSumData/** = perms [api: data]/api/** = perms [api: *]... /** = anon </value> </property> </bean> <bean id = "securityManager" class = "org. apache. shiro. web. mgt. defaultWebSecurityManager "> <property name =" realm "ref =" permissionsRealm "/> <! -- Customize the source for logging in and obtaining permissions --> </bean> <! -- Shiro permission management configuration end -->
Add the shiro filter configuration in web. xml:

<Context-param> <param-name> contextConfigLocation </param-name> <param-value> classpath *: applicationContext. xml, classpath *: spring -*. xml // spring-shiro </param-value> </context-param> is introduced here... <filter> <filter-name> shiroFilter </filter-name> <filter-class> org. springframework. web. filter. delegatingFilterProxy </filter-class> </filter> <filter-mapping> <filter-name> shiroFilter </filter-name> <url-pattern>/* </url-pattern> </filter-mapping>

3. Define the source for logging in and obtaining permissions.

/*** Authentication implementation class ** @ author kexm **/@ Service ("secret") public class permissionsRealm extends AuthorizingRealm {@ Autowired private AccountDao accountDao; @ Autowired private GroupDao groupDao; private Account acc; private static LogUtil log = LogUtil. getLogger (PermissionsRealm. class);/*** user permission source (shiro calls this method to obtain user permissions. We define where to obtain permission items .) * // @ Override protected AuthorizationInfo doGetAuthorizationInfo (PrincipalCollection principals) {SimpleAuthorizationInfo info = new SimpleAuthorizationInfo (); log.info ("method [doGetAuthorizationInfo] begin."); if (acc! = Null) {if (acc. getAdminType () = 2) {// The Super administrator always has all the permissions info. addStringPermission ("*"); return info;} try {List <UserGroup> gList = accountDao. getUserGroups (acc. getLoginName (); for (UserGroup g: gList) {// obtain the user's group log.info ("method [doGetAuthorizationInfo] group <" + g. getName () + ">"); List <Permission> pList = groupDao. getGroupPerms (g. getId (); for (Permission p: pList) {// obtain the Group Permission log.info ("method [doG EtAuthorizationInfo] perm <"+ p. getName () +", "+ p. getPermList () +"> "); String permList = p. getPermList (); if (permList! = Null &&! "". Equals (permList) {String [] perms = p. getPermList (). split (","); for (String perm: perms) {// put the permissions in the container (the permissions are presented in String format, such as "api: data, corresponds to the configuration in the spring-shiro.xml) log.info ("method [doGetAuthorizationInfo] add perm <" + perm + ">"); info. addStringPermission (perm) ;}}} return info; // return the user permission to shiro} catch (Exception e) {log. error ("method [doGetAuthorizationInfo] e. message <"+ e. getMessage () + "> e <" + e + "> ", E) ;}} return null;}/*** User Logon verification source (shiro calls this method for authentication) */@ Override protected AuthenticationInfo doGetAuthenticationInfo (AuthenticationToken authtoken) throws AuthenticationException {log.info ("method [doGetAuthenticationInfo] begin. "); UsernamePasswordToken token = (UsernamePasswordToken) authtoken; SimpleAuthenticationInfo authenticationInfo = null; String userName = token. getUsername (); String Password = new String (token. getPassword (); Login conf = DefaultConfigure. config. getLogin (); String MD5pwd = MD5Util. generateSignature (conf. getSalt (), password); try {if (userName! = Null &&! "". Equals (userName) {acc = accountDao. login (userName, MD5pwd);} if (acc! = Null) {doGetAuthorizationInfo (SecurityUtils. getSubject (). getPrincipals (); authenticationInfo = new SimpleAuthenticationInfo (token. getUsername (), token. getPassword (), getName (); return authenticationInfo ;}} catch (Exception e) {log. error ("method [doGetAuthenticationInfo] acc <" + acc + "> message <" + e. getMessage () + "> e <" + e + ">", e) ;}return null ;}}

3. Use subject to manage users in shiro. Subject can be understood as a shiro container for storing user information and a tool for manipulating users. With the configuration in the previous steps, you can use the following code to log on and log out and enjoy shiro url permission control.

// Log on to UsernamePasswordToken token = new UsernamePasswordToken (loginName, password); Subject user = SecurityUtils. getSubject (); user. login (token); // use the session that comes with shiro to store user information independent of httpSession Session ss = user. getSession (). setAttribute ("userInfo", acc); // log out of SecurityUtils. getSubject (). logout ();

4. Use the shiro tag on the page. If you want a user with permissions to view some menus or buttons, you can use the following methods.

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %><shiro:hasPermission name="api:data">        who has permission can see</shiro:hasPermission>


Only the permission management of shiro is used. shiro also supports the management of role, which can be used if further abstraction is required.


2. Distributed Environment, combining shiro with redis

If our web project is deployed in a distributed manner, let shiro put the session and user permissions to the centralized cache. Shiro does not implement Cache, but provides interfaces to facilitate the replacement of different underlying Cache implementations.

Shiro provides the cache interface:


Public interface Cache <K, V> {// obtain the value of public V get (K Key) throws CacheException in the Cache based on the key; // put the key-value in the Cache, returns the value public V put (K key, V value) throws CacheException in the cache; // removes the value corresponding to the key in the cache, and returns the value public V remove (K key) throws CacheException; // clear the entire cache public void clear () throws CacheException; // return the cache size public int size (); // obtain all the keys in the cache public Set <K> keys (); // obtain all values in the cache public Collection <V> values ();}

We can observe the interface and find that we need to implement a keys method.This method limits shiro's inability to use the cache cluster (SharedRedis does not provide this method, only a single redis can use the keys method, hope to find a solution ).


Our project uses redis as a centralized cache. shiro and redis can be combined to use a ready-made tool-shiro-redis.

Shiro-redis github: https://github.com/alexxiyang/shiro-redis

This tool is currently in use for management background projects. This tool has one problem: when reading the cache, it does not extend the validity period of the read object. It is quite useful after fixing this BUG.


3. Expand the shiro page tag and add and or not logical operators

Reference: http://jinnianshilongnian.iteye.com/blog/1864800

Friends who have used shiro should know that it is troublesome to implement any permission verification.

Many of my friends thought that <shiro: hasPermission name = "showcase: tree: *"> was used to verify that the user has any permissions under the tree, but this is incorrect. If we grant the showcase: tree: * permission to the user, it indicates that the user has any permissions for the showcase: tree resource, such as <shiro: hasPermission name = "showcase: tree: * "> or shiro: hasPermission name =" showcase: tree: create "> the verification is successful.

Some friends think that <shiro: hasPermission name = "showcase: tree: create, update"> is the or not. The default value is the same.

The latest shiro1.3.0-SNAPSHOT is downloaded and no new tags or other support is added.

Therefore, we need to simply extend shiro to support the powerful annotation of @ Secured support expressions like spring security 3. We extended AuthorizingRealm and modified:

Private static final String OR_OPERATOR = "or"; private static final String AND_OPERATOR = "and"; private static final String NOT_OPERATOR = "not "; /*** support for or and not keywords not support and or mixing * @ param principals * @ param permission * @ return */public boolean isPermitted (PrincipalCollection principals, String permission) {if (permission. contains (OR_OPERATOR) {String [] permissions = permission. split (O R_OPERATOR); for (String orPermission: permissions) {if (isPermittedWithNotOperator (principals, orPermission) {return true ;}} return false;} else if (permission. contains (AND_OPERATOR) {String [] permissions = permission. split (AND_OPERATOR); for (String orPermission: permissions) {if (! IsPermittedWithNotOperator (principals, orPermission) {return false ;}return true ;}else {return principal (principals, permission) ;}} private boolean evaluate (PrincipalCollection principals, String permission) {if (permission. startsWith (NOT_OPERATOR) {return! Super. isPermitted (principals, permission. substring (NOT_OPERATOR.length ();} else {return super. isPermitted (principals, permission );}}

The code above can implement simple NOT, AND, OR support, but the disadvantage is that it does NOT support complex combinations such as and or.

The following labels can take effect after expansion:

<shiro:hasPermission name="api:data or api:user"></shiro:hasPermission><pre name="code" class="html"><shiro:hasPermission name="api:data and api:user"></shiro:hasPermission> 
<shiro:hasPermission name="not api:data"></shiro:hasPermission>


 

 

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.