近期由于使用shiro作为安全框架作为项目中要使用的权限管理,在此分享一下shiro于spring和springmvc集成的demo
1.首先添加web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app 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_3_0.xsd" version="3.0" metadata-complete="true"> <display-name>shiro测试</display-name> <!-- shiroFilter --> <filter> <filter-name>shiroFilter</filter-name> <!-- 代理类,自动到spring配置文件中找shiro配置文件 --> <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> </filter-mapping> <!-- 加载spring配置文件 --> <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> <!-- springmvc配置文件加载 --> <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>/</url-pattern> </servlet-mapping> <!-- 使用spring解决乱码问题 --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file>login.jsp</welcome-file> </welcome-file-list> </web-app>
2.SpringMVC配置文件springmvc.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:mvc="http://www.springframework.org/schema/mvc" 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.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd "> <!-- <bean id="myController" name="/control.action" class="com.cai.controller.MyController"></bean> --> <!-- 支持注解驱动 --> <mvc:annotation-driven/> <!-- shiro中注解起作用必须配置在springmvc配置文件中,配置在其他地方无效 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true" /> </bean> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> <!-- 配置异常跳转页面,此处异常页面是使用shiro注解时没有权限访问的跳转页面,不配置则会报500错误 --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="org.apache.shiro.authz.UnauthorizedException"> <!-- 没有权限时跳转的页面 --> /unauthorized </prop> <prop key="org.apache.shiro.authz.UnauthenticatedException"> <!-- 认证错误时跳转的页面 --> /unauthenticated </prop> </props> </property> </bean> <!-- 组件扫描的包 --> <context:component-scan base-package="com.cai.controller"/> <!-- 静态资源目录 --> <mvc:resources mapping="/js/**" location="/js/" /> <mvc:resources mapping="/images/**" location="/images/" /> <mvc:resources mapping="/css/**" location="/css/" /> <mvc:resources mapping="/common/**" location="/common/" /> <!-- 配置视图解析器 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 通过setter方法注入前缀 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 通过setter方法注入后缀 --> <property name="suffix" value=".jsp"></property> </bean> </beans>
3.Spring配置文件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:mvc="http://www.springframework.org/schema/mvc" 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.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd "> <!-- 组件扫描 --> <context:component-scan base-package="com.cai.*"/> <!--数据库配置:配置jdbc.properties --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 3、配置dataSource数据源c3p0 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClassName}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <!-- <property name="maxPoolSize" value="${c3p0.pool.maxPoolSize}"/> <property name="minPoolSize" value="${c3p0.pool.minPoolSize}"/> <property name="initialPoolSize" value="${c3p0.pool.initialPoolSize}"/> <property name="acquireIncrement" value="${c3p0.pool.acquireIncrement}"/> --> </bean> <!-- 数据源使用Spring自带的jdbctemplate --> <bean id="jdbcTemplate" name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="userDao" name="userDao" class="com.cai.dao.UserDao"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> <bean id="baseDao" name="baseDao" class="com.cai.dao.BaseDao"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> <!-- <bean id="baseDao" name="baseDao" class="com.cai.dao.BaseDao"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> --> <!-- 事务管理 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 导入shiro配置文件 --> <import resource="shiro.xml"/> </beans>
4.jdbc.properties
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/shiro?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8 jdbc.username=root jdbc.password=123456
5.缓存ehcache.xml
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true" monitoring="autodetect" dynamicConfig="true"> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> </ehcache>
6.java代码
MD5加密
public class MD5Utils { /** * 使用md5的算法进行加密 * 此处使用的是shiro自带的md5加密方法 */ public static String md5(String password) { Md5Hash md5 = new Md5Hash(password); return md5.toString(); } }
实体类javabean
public class User { private int id; private String username;//用户名 private String password;//用户密码 private String realname;//真实名字 private String email;//emai地址 private String phone;//电话号码 private List<Role> roles = new ArrayList<Role>(); /** * @return the roles */ public List<Role> getRoles() { return roles; } /** * @param roles the roles to set */ public void setRoles(List<Role> roles) { this.roles = roles; } ....都是get、set方法 }
public class Role { private int id; private String rolename;//角色名 private String roletype;//角色类型 List<Permission> perms = new ArrayList<Permission>(); /** * @return the perms */ public List<Permission> getPerms() { return perms; } /** * @param perms the perms to set */ public void setPerms(List<Permission> perms) { this.perms = perms; } //...get set方法 }
public class Permission { private int id; private String permname;//权限名称 private String operation;//权限操作 private String description;//权限描述 /** * @return the id */ public int getId() { return id; } /** * @param id the id to set */ public void setId(int id) { this.id = id; } //...get set方法 }
Dao层
@Repository public class BaseDao extends JdbcDaoSupport { /** * 条件查询 * @param sql * @param id * @return */ public Map<String, Object> querySingle(String sql,Object... args) { return this.getJdbcTemplate().queryForMap(sql, args); } /** * 根据sql查询 * @param sql * @return */ public Map<String, Object> queryAll(String sql) { return this.getJdbcTemplate().queryForMap(sql); } /** * 查询集合 * @param sql * @return */ public List<Map<String, Object>> queryList(String sql) { return this.getJdbcTemplate().queryForList(sql); } /** * 条件查询集合 * @param sql * @param args * @return */ public List<Map<String, Object>> queryList(String sql, Object... args) { return this.getJdbcTemplate().queryForList(sql, args); } /** * 更新记录条数 * @param sql * @return */ public int update(String sql) { return this.getJdbcTemplate().update(sql); } /** * 按条件更新 * @param sql * @param args * @return */ public int update(String sql, Object... args) { return this.getJdbcTemplate().update(sql, args); } /** * 添加记录 * @param sql */ public void add(String sql) { this.getJdbcTemplate().execute(sql); } /** * 删除记录 * @param sql */ public void delete(String sql) { this.getJdbcTemplate().execute(sql); } }
@Repository public class UserDao extends JdbcDaoSupport { /** * 登录查询 * @param sql * @param username * @param password * @return */ public Map<String, Object> loginQuery(String sql, String username, String password) { return this.getJdbcTemplate().queryForMap(sql, username, password); } /** * 登录查询 * @param sql * @param username * @param password * @return */ public Map<String, Object> loginQuery(String sql, String username) { return this.getJdbcTemplate().queryForMap(sql, username); } }
Service 层
@Service public class UserService { @Autowired UserDao userDao; @Autowired BaseDao baseDao; public Map<String, Object> queryLogin(String username, String password) { String sql = "select username, password from user where username=? and password=?"; return userDao.loginQuery(sql, username, password); } public User queryLogin(String username) { String sql = "select * from user where username=?"; Map<String, Object> query = userDao.loginQuery(sql,username); User user = new User(); if(query != null && query.size() > 0) { if(query.get("id") != null) { user.setId(Integer.parseInt(query.get("id").toString())); } if(query.get("username") != null) { user.setUsername(query.get("username").toString()); } if(query.get("password") != null) { user.setPassword(query.get("password").toString()); } if(query.get("realname") != null) { user.setRealname(query.get("realname").toString()); } if(query.get("email") != null) { user.setEmail(query.get("email").toString()); } if(query.get("phone") != null) { user.setPhone(query.get("phone").toString()); } } return user; } }
@Service public class ShiroService { @Autowired BaseDao baseDao; /** * 根据角色id获取对应的权限id * @param roleid * @return */ public List<Map<String, Object>> getPermissions(int roleid) { String sql = "select * from role_permission where role_id=?"; return baseDao.queryList(sql, roleid); } /** * 通过用户id获取角色 * @param userid * @return */ public List<Map<String, Object>> getRoles(int userid){ String sql = "select * from role where id in (select role_id from user_role where user_id=?)"; return baseDao.queryList(sql, userid); } /** * 添加权限id * @param permid */ /*public void addPerm(int permid) { String sql = "insert into role_permission"; }*/ /** * 查询所有的权限 * @param role * @return */ public List<Map<String, Object>> getPermissions(Role role) { String sql = "select * from permission where id in (SELECT permission_id from role_permission WHERE role_id=?)"; return baseDao.queryList(sql, role.getId()); } /** * 查询所有的角色 * @param user * @return */ public List<Map<String, Object>> getRoles(User user) { String sql = "select * from role where id in (select role_id from user_role where user_id=?)"; return baseDao.queryList(sql, user.getId()); } }
Shiro核心
@Service public class MyRealm extends AuthorizingRealm{ @Autowired ShiroService shiroService; @Autowired UserService userService; /* (non-Javadoc) * @see org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection) * 授权 */ @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); //获取当前登录用户名 //String account = (String) principals.fromRealm(getName()).iterator().next(); // String account = (String)getAvailablePrincipal(principals); Subject subject = SecurityUtils.getSubject(); String account = (String) subject.getPrincipal(); User user = userService.queryLogin(account); List<Map<String,Object>> roleList = shiroService.getRoles(user); for (Map<String, Object> roles : roleList) { authorizationInfo.addRole(roles.get("roletype").toString()); Role role = new Role(); role.setId(Integer.parseInt((roles.get("id").toString()))); List<Map<String, Object>> permissionsList = shiroService.getPermissions(role); for (Map<String, Object> perms : permissionsList) { authorizationInfo.addStringPermission(perms.get("operation").toString()); } } return authorizationInfo; } /* (non-Javadoc) * @see org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken) * 认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { //根据用户名查询数据库 UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token;//封装认证对象 User user = userService.queryLogin(usernamePasswordToken.getUsername()); if(user == null) { //用户不存在 return null; } //返回密码 AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());//getName获取当前的realm //比较密码 return authenticationInfo; } }
Controller
@Controller public class UserController { @Autowired UserService userService; @RequestMapping(value="/login") public String login (HttpServletRequest request) { //非shiro登录 /*String username = request.getParameter("username"); String password = request.getParameter("password"); Map<String, Object> queryLogin = userService.queryLogin(username, MD5Utils.md5(password)); if(queryLogin != null) { return "success"; } else { return "fail"; }*/ return "login"; } @RequestMapping(value="/checklogin") @ResponseBody public String checkLogin(HttpServletRequest request) { String username = request.getParameter("username"); String password = request.getParameter("password"); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, MD5Utils.md5(password)); token.setRememberMe(true); try { subject.login(token); request.getSession().setAttribute("account", username); } catch (AuthenticationException e) { //e.printStackTrace(); return "/login"; } return "/first"; } @RequestMapping(value="/manage/first") public String main(HttpServletRequest request) { //String return "/manage/first"; } @RequestMapping(value="/operation/add") public String add(HttpServletRequest request) { return "/operation/add"; } //@RequiresRoles("administrator") @RequestMapping(value="/operation/delete") public String delete(HttpServletRequest request) { Subject subject = SecurityUtils.getSubject(); if(subject.hasRole("administrator")) { return "/operation/delete"; } else { return "/manage/unauthorized"; } } @RequestMapping(value="/operation/update") @RequiresRoles("header") public String update(HttpServletRequest request) { return "/operation/update"; } @RequestMapping(value="/operation/query") public String query(HttpServletRequest request) { return "/operation/query"; } @RequestMapping(value="/search/search") public String search(HttpServletRequest request) { return "/search/search"; } @RequestMapping(value="/manage/unauthorized") public String error(HttpServletRequest request) { return "/manage/unauthorized"; } @RequestMapping(value="/logout", method=RequestMethod.GET) public String logout() { Subject subject = SecurityUtils.getSubject(); if(subject.isAuthenticated()) { subject.logout(); //return "login"; } return "redirect:login"; } }
jsp页面在下面的文件中,下载后创建数据库执行sql,直接导入项目就行 了