虽然网上很多关于Shiro的样例,但是LZ看了很多,觉得他们好多都不是自己想要的。
不是没有URL过滤功能,就是写死在xml配置文件里,还有好多不能使。
LZ不才,只能写一些简单样例给大家看看。
基础要求:SSH都会,了解权限管理的架构。
接下来是代码:
先给出表
CREATE TABLE `t_privilege` ( `id` int(11) NOT NULL auto_increment, `perms` varchar(255) default NULL, `url` varchar(255) default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; CREATE TABLE `t_user` ( `id` int(11) NOT NULL auto_increment, `password` varchar(255) default NULL, `username` varchar(255) default NULL, `role_id` int(11) default NULL, PRIMARY KEY (`id`), KEY `FKCB63CCB613F1722F` (`role_id`), CONSTRAINT `FKCB63CCB613F1722F` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; CREATE TABLE `t_role` ( `id` int(11) NOT NULL, `name` varchar(255) default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `t_role_t_privilege` ( `t_role_id` int(11) NOT NULL, `privileges_id` int(11) NOT NULL, PRIMARY KEY (`t_role_id`,`privileges_id`), KEY `FK6947A6C85C5EE234` (`privileges_id`), KEY `FK6947A6C8CF836564` (`t_role_id`), CONSTRAINT `FK6947A6C8CF836564` FOREIGN KEY (`t_role_id`) REFERENCES `t_role` (`id`), CONSTRAINT `FK6947A6C85C5EE234` FOREIGN KEY (`privileges_id`) REFERENCES `t_privilege` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
这里设计的就是一个User,一个Role。但是Role有很多的URL。
DAO,Service 就不给了。
action:
package com.vti.action; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import com.vti.model.User; import com.vti.service.UserService; @Controller @RequestMapping(value="/") public class LoginController { private UserService userService; public UserService getUserService() { return userService; } @Resource public void setUserService(UserService userService) { this.userService = userService; } @RequestMapping(value = "/login") public String login(String username, String password, ModelMap map){ if(this.userService.checkUser(username, password)){ setLogin(username, password); return "index.do"; }else{ map.addAttribute("msg", "username or password error !"); return "login.jsp"; } } @RequestMapping(value = "/index") public String index(HttpServletRequest request, HttpServletResponse response,ModelMap map){ Subject currentUser = SecurityUtils.getSubject(); User user=userService.getByUserLoginId(currentUser.getPrincipal().toString()); map.addAttribute("LoginUser",user); return "index.jsp"; } @RequestMapping(value = "/logout") public String logout(HttpServletRequest request, HttpServletResponse response,ModelMap map){ Subject currentUser = SecurityUtils.getSubject(); currentUser.logout(); return "login.jsp"; } private void setLogin(String userName, String password) { Subject currentUser = SecurityUtils.getSubject(); if (!currentUser.isAuthenticated()) { UsernamePasswordToken token = new UsernamePasswordToken(userName, password); token.setRememberMe(false); currentUser.login(token); } } }
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <welcome-file-list> <welcome-file>login.jsp</welcome-file> </welcome-file-list> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:beans.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> <dispatcher>ERROR</dispatcher> </filter-mapping> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:SpringMVC.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app>
beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"> <context:annotation-config /> <context:component-scan base-package="com.vti"></context:component-scan> <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/test" /> <property name="username" value="root" /> <property name="password" value="admin" /> <property name="initialSize" value="5" /> <property name="maxActive" value="500" /> <property name="maxIdle" value="50" /> <property name="minIdle" value="10" /> <property name="timeBetweenEvictionRunsMillis" value="3600000" /> <property name="minEvictableIdleTimeMillis" value="3600000" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="packagesToScan"> <list> <value>com.vti.model</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <aop:config> <aop:pointcut id="bussinessService" expression="execution(public * com.vti.service.*.*(..))" /> <aop:advisor pointcut-ref="bussinessService" advice-ref="txAdvice" /> </aop:config> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED"/> <tx:method name="find*" read-only="true"/> <tx:method name="get*" read-only="true"/> </tx:attributes> </tx:advice> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="shiroDbRealm" /> </bean> <bean id="shiroDbRealm" class="com.vti.shiro.MyShiroRealm" /> <bean id="chainDefinitionSectionMetaSource" class="com.vti.shiro.ChainDefinitionSectionMetaSource"> <property name="filterChainDefinitions"> <value> /login.do = anon /logout.do = logout </value> </property> </bean> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <property name="loginUrl" value="/login.jsp" /> <property name="successUrl" value="/index.do" /> <property name="unauthorizedUrl" value="/403.htm" /> <property name="filterChainDefinitionMap" ref="chainDefinitionSectionMetaSource" /> </bean> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor" > </bean> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> </beans>
ChainDefinitionSectionMetaSource
package com.vti.shiro; import java.text.MessageFormat; import java.util.Iterator; import java.util.List; import javax.annotation.Resource; import org.apache.shiro.config.Ini; import org.apache.shiro.config.Ini.Section; import org.springframework.beans.factory.FactoryBean; import org.springframework.util.StringUtils; import com.vti.dao.PrivilegeDao; import com.vti.model.Privilege; public class ChainDefinitionSectionMetaSource implements FactoryBean<Ini.Section>{ public static final String PREMISSION_STRING="perms[\"{0}\"]"; private String filterChainDefinitions; private PrivilegeDao privilegeDao; public PrivilegeDao getPrivilegeDao() { return privilegeDao; } public String getFilterChainDefinitions() { return filterChainDefinitions; } @Resource public void setFilterChainDefinitions(String filterChainDefinitions) { String fiter="";//改正后的url配置 List<Privilege> list = privilegeDao.getAll(); for (Iterator<Privilege> it = list.iterator(); it.hasNext();) { Privilege privilege = it.next(); if(!StringUtils.isEmpty(privilege.getUrl())) { fiter+="/"+privilege.getUrl()+" = authc," +MessageFormat.format(PREMISSION_STRING,privilege.getPerms()) +"\n"; }//追加beans.xml中已经有的过滤 } System.out.println(filterChainDefinitions+fiter); this.filterChainDefinitions = filterChainDefinitions+fiter; } @Resource public void setPrivilegeDao(PrivilegeDao privilegeDao) { this.privilegeDao = privilegeDao; } public Section getObject(){ Ini ini = new Ini();//网上好多都是在这里配置URL的。但是发现是错误的。 ini.load(filterChainDefinitions); Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME); return section; } public Class<?> getObjectType() { return this.getClass(); } public boolean isSingleton() { return false; } }
MyShiroRealm
package com.vti.shiro; import java.util.List; import javax.annotation.Resource; import org.apache.shiro.authc.AccountException; 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.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.util.StringUtils; import com.vti.model.Privilege; import com.vti.model.User; import com.vti.service.UserService; public class MyShiroRealm extends AuthorizingRealm{ private UserService userService; public UserService getUserService() { return userService; } @Resource public void setUserService(UserService userService) { this.userService = userService; } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { if(principals == null){ throw new AuthorizationException("principals should not be null"); } SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); String username =(String) principals.fromRealm(this.getName()).iterator().next(); List<Privilege> privileges = userService.getAllPrivilegeByUserId(username); for(Privilege p : privileges){ info.addStringPermission(p.getPerms()); } return info; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authecToken){ UsernamePasswordToken token = (UsernamePasswordToken)authecToken; if(StringUtils.isEmpty(token.getUsername())){ throw new AccountException("用户名不能为空"); } User user = userService.getByUserLoginId(token.getUsername()); if(user == null){ throw new UnknownAccountException("用户名没找到"); } else if(user.getPassword().equals(new String(token.getPassword()))){ return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), this.getName()); } else { throw new AuthenticationException("授权失败"); } } }
给出index,jsp
有shiro的标签使用
<%@ page language="java" contentType="text/html; utf-8" pageEncoding="utf-8"%> <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; utf-8"> <title>Insert title here</title> </head> <body> <shiro:authenticated> <h3>Login User Can see it</h3> <h4>You are ${LoginUser.role.name}, Your name is ${LoginUser.username}</h4> </shiro:authenticated> <shiro:hasPermission name="set"> <a href="3.jsp">系统设置</a><br> </shiro:hasPermission> <shiro:hasPermission name="view"> <a href="2.jsp">总账查看</a><br> </shiro:hasPermission> <shiro:hasPermission name="sale"> <a href="1.jsp">卖货</a><br><br> </shiro:hasPermission> <shiro:notAuthenticated> Please <a href="login.jsp">login</a> in order to update your credit card information. </shiro:notAuthenticated> <shiro:authenticated> <a href="logout.do">注销</a> </shiro:authenticated> </body> </html>
最后讲下逻辑思路:
系统分为三个等级。 分别是:售货员,经理,管理员
售货员:登录,卖货,注销
经理:查账,登录,卖货,注销
管理员:系统设置,查账,登录,卖货,注销。
主要是围绕这样的功能去分配url的。
数据库在附件中给出。