springmvc+spring+mybatis+shrio+mysql
来源:互联网 发布:dede企业网站源码 编辑:程序博客网 时间:2024/05/21 17:21
shrio的作用已经不用说了,就直接说用吧,当然我们的系统要求没有很高,所以我也学习的比较简单。
第一步:jar
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.2</version> </dependency>
第二步:配置web.xml
<context-param> <param-name>contextConfigLocation</param-name> <!--加载springmvc和spring配置文件的位置,添加sprin- shiro.xml--!> <param-value>classpath:spring/applicationContext-*.xml,classpath:spring/spring-shiro.xml</param-value></context-param><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></filter-mapping>
第三步:
spring-shrio.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" default-lazy-init="true"> <description>Shiro Configuration</description> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <!--设置自定义realm --> <property name="realms" ref="monitorRealm" /> <!-- 缓存管理器 --> <property name="cacheManager" ref="cacheManager"/> </bean> <!-- 会话管理器 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <!-- 设置超时时间 --> <property name="globalSessionTimeout" value="18000"/> <property name="deleteInvalidSessions" value="true"/> <property name="sessionValidationSchedulerEnabled" value="true"/> <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/> <property name="sessionDAO" ref="sessionDAO"/> <property name="sessionIdCookieEnabled" value="true"/> <property name="sessionIdCookie" ref="sessionIdCookie"/> </bean> <!--自定义Realm 继承自AuthorizingRealm --> <bean id="monitorRealm" class="com.yzb.loanplatform.manager.util.shrio.ShrioRealm"> <property name="credentialsMatcher"> <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <property name="hashAlgorithmName" value="MD5"/> <!--true means hex encoded, false means base64 encoded --> <property name="storedCredentialsHexEncoded" value="true"/> <!-- 迭代次数 --> <property name="hashIterations" value="1024" /> </bean> </property> </bean> <!-- Shiro主过滤器本身功能十分强大,其强大之处就在于它支持任何基于URL路径表达式的、自定义的过滤器的执行 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <!-- 要求登录时的链接,非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 --> <property name="loginUrl" value="/login" /> <!-- 用户访问未对其授权的资源时,所显示的连接 --> <!-- <property name="unauthorizedUrl" value="/error/noperms.jsp" /> --> <property name="filterChainDefinitions"> <value> <!-- Anon:不指定过滤器 Authc:验证,这些页面必须验证后才能访问,也就是我们说的登录后才能访问。 --> /login.ftl = anon /system/**= authc /orderInfo/findOrderInfo= authc /orderInfo/ucfRefundCallback= anon /static/**=anon </value> </property> </bean> <!-- 用户授权信息Cache --> <bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" /> <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <!-- AOP式方法级权限检查 --> <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></beans>
第四步:springmvc中配置:其作用是在conroller中使用注解方法实现权限拦截
<!-- 为使用AOP注解方式控制权限 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true" /> </bean>
以上配置就是所有配置,现在仔细说下spring-shrio.xml中的几个重点:
1,自定义的realm:shrio中核心,有SecurityManager管理,
<bean id="securityManager"class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <!--设置自定义realm --> <property name="realms" ref="monitorRealm" /></bean>
<!--自定义Realm 继承自AuthorizingRealm --><bean id="monitorRealm" class="**com.yzb.loanplatform.manager.util.shrio.ShrioRealm**"> <property name="credentialsMatcher"> <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <!-- 密码加密方式 --> <property name="hashAlgorithmName" value="MD5"/> <property name="storedCredentialsHexEncoded" value="true"/> <!-- 次数加密次数 --> <property name="hashIterations" value="1024" /> </bean> </property> </bean>
重点来了,ShrioRealm.java用来实现登陆身份验证和首选操作;
package com.yzb.loanplatform.manager.util.shrio;import java.util.ArrayList;import java.util.List;import org.apache.commons.lang3.StringUtils;import org.apache.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.LockedAccountException;import org.apache.shiro.authc.SimpleAuthenticationInfo;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.apache.shiro.util.ByteSource;import org.springframework.beans.factory.annotation.Autowired;import com.yzb.loanplatform.pojo.Employee;import com.yzb.loanplatform.pojo.Permission;import com.yzb.loanplatform.pojo.Role;import com.yzb.loanplatform.service.EmployeeService;import com.yzb.loanplatform.vo.EmployeeVo;/** * @ClassName: ShrioRealm * @Description: TODO(这里用一句话描述这个类的作用) * @author zhaofq * @date 2017年8月10日 */public class ShrioRealm extends AuthorizingRealm { private static Logger loger = Logger.getLogger(ShrioRealm.class.getName()); @Autowired private EmployeeService employeeService; /** * 授权操作 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 获取当前登录的用户名,等价于(String)principals.fromRealm(this.getName()).iterator().next() String account = (String) super.getAvailablePrincipal(principals); EmployeeVo employeeVo = new EmployeeVo(); employeeVo.setPhone(account); List<String> roles = new ArrayList<String>(); List<String> permissions = new ArrayList<String>(); // //从数据库中获取当前登录用户的详细信息 Employee employee = employeeService.getEmployeeRoleAanPermissions(employeeVo); if (employee != null) { // 实体类User中包含有用户角色的实体类信息 if (employee.getRoleList() != null && employee.getRoleList().size() > 0) { // 获取当前登录用户的角色 for (Role role : employee.getRoleList()) { roles.add(role.getRoleCode()); // 实体类Role中包含有角色权限的实体类信息 if (role.getPermissionList() != null && role.getPermissionList().size() > 0) { // 获取权限 for (Permission pmss : role.getPermissionList()) { if (!StringUtils.isEmpty(pmss.getUrl())) { permissions.add(pmss.getUrl()); } } } } } } else { throw new AuthorizationException(); } // 为当前用户设置角色和权限 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addRoles(roles); info.addStringPermissions(permissions); return info; } /** * 身份验证操作 */ @SuppressWarnings("unused") @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; String userName = String.valueOf(token.getPrincipal()); // 得到身份(用户名) String passWord = new String((char[]) token.getCredentials()); // 得到认证/凭证(密码) // 从数据库中查询用户用信息 EmployeeVo employeeVo = new EmployeeVo(); employeeVo.setPhone(userName); Employee employee = employeeService.getEmployee(employeeVo); Employee employee2 = employeeService.getEmployeeRoleAanPermissions(employeeVo); if (employee != null) { if ("1".endsWith(employee.getStatus().toString())) { // 判断帐号是否锁定 throw new LockedAccountException();// 抛出 帐号锁定异常 } // 此处无需比对,比对的逻辑Shiro会做,我们只需返回一个和令牌相关的正确的验证信息 byte[] myByte = employee.getSalt().getBytes(); SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(employee.getPhone(), employee.getEmpPassword(), ByteSource.Util.bytes(myByte), this.getName()); // simpleAuthenticationInfo.setCredentialsSalt(salt); return simpleAuthenticationInfo; } else { // 没有返回登录用户名对应的SimpleAuthenticationInfo对象时,就会在LoginController中抛出UnknownAccountException异常 return null; } } @Override public void clearCachedAuthorizationInfo(PrincipalCollection principals) { super.clearCachedAuthorizationInfo(principals); } @Override public void clearCachedAuthenticationInfo(PrincipalCollection principals) { super.clearCachedAuthenticationInfo(principals); } @Override public void clearCache(PrincipalCollection principals) { super.clearCache(principals); } public void clearAllCachedAuthorizationInfo() { getAuthorizationCache().clear(); } public void clearAllCachedAuthenticationInfo() { getAuthenticationCache().clear(); } public void clearAllCache() { clearAllCachedAuthenticationInfo(); clearAllCachedAuthorizationInfo(); }}
有两个重要的方法:
1,doGetAuthenticationInfo:用来做身份认证,当用户输入用户名密码后在登陆的controller中通过:
UsernamePasswordToken token = new UsernamePasswordToken(username,password); Subject currentUser = SecurityUtils.getSubject(); token.setRememberMe(true); currentUser.login(token);
实现对doGetAuthenticationInfo的调用,具体作用就是把页面发送过来的用户名和密码传入到doGetAuthenticationInfo方法中,
使用用户名去重是否有对应的用户,如果找到就调用shrio内部的密码校验方法,
// 此处无需比对,比对的逻辑Shiro会做,我们只需返回一个和令牌相关的正确的验证信息 byte[] myByte = employee.getSalt().getBytes(); SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(employee.getPhone(), employee.getEmpPassword(), ByteSource.Util.bytes(myByte), this.getName()); // simpleAuthenticationInfo.setCredentialsSalt(salt); return simpleAuthenticationInfo;
这里你只需要把你你查询数据获取到的用户名,密码,言放到SimpleAuthenticationInfo就可以了,可以看看看看源码是怎么实现的校验的,不再多说,
根据返回校验结果就会提示是否校验通过。
2,授权方法:doGetAuthorizationInfo:就是查看操作用户拥有的资源权限,
主要是根据用户名获取对应角色,权限的资源。
次方法调用时在controller总通过注解的方式:
@RequiresRoles(logical=Logical.OR,value={“admin”,”adminEmp”})
页面时通过shrio标签。
<shiro:hasAnyRoles name="admin,adminEmp" ><li><a href="${request.contextPath}/employee/employeePage">员工管理</a></li></shiro:hasAnyRoles>
当然我这里是把菜单写死了,所以不能控制菜单是否显示,而是在操作时提示没有权限,
原理大概是党操作菜单之后就会通过@RequiresRoles查看当强用户是否用户此角色,角色是否用户权限。
当也有直接控制按钮的方式我就不在说了,
public class BaseController { /** * 登录认证异常 */ @ExceptionHandler({ UnauthenticatedException.class, AuthenticationException.class }) public String authenticationException(HttpServletRequest request, HttpServletResponse response) { if (WebUtilsPro.isAjaxRequest(request)) { // 输出JSON Map<String,Object> map = new HashMap<>(); map.put("code", "-999"); map.put("message", "未登录"); return null; } else { return "redirect:/system/login"; } } /** * 权限异常 */ @ExceptionHandler({ UnauthorizedException.class, AuthorizationException.class,ServletException.class }) public String authorizationException(HttpServletRequest request, HttpServletResponse response) { DataResponse data = new DataResponse(); // 输出JSON Map<String,Object> map = new HashMap<>(); map.put("code", "-999"); map.put("msg", "无权限"); data.setCode(200); data.setData(map); return "/notPermission"; }}
登陆异常和无权限时提示,让每个使用权限的controller继承此controler就可以了,
最后角色权限表:
DROP TABLE IF EXISTS `MTB_ROLE`;CREATE TABLE `MTB_ROLE` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(10) DEFAULT NULL, `description` varchar(50) DEFAULT NULL, `roleCode` varchar(255) DEFAULT NULL, PRIMARY KEY (`Id`)) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4;
DROP TABLE IF EXISTS `MTB_PERMISSION`;CREATE TABLE `MTB_PERMISSION` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL, `description` varchar(200) DEFAULT NULL, `url` varchar(255) DEFAULT NULL, PRIMARY KEY (`Id`)) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4;
DROP TABLE IF EXISTS `MTB_ROLE_PERMISSION`;CREATE TABLE `MTB_ROLE_PERMISSION` ( `id` int(11) NOT NULL AUTO_INCREMENT, `role_Id` int(36) DEFAULT NULL, `permission_Id` int(36) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8mb4;
DROP TABLE IF EXISTS `MTB_EMPLOYEE_ROLE`;CREATE TABLE `MTB_EMPLOYEE_ROLE` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `employee_Id` int(36) DEFAULT NULL, `role_Id` int(36) DEFAULT NULL, PRIMARY KEY (`Id`)) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4;
还有一个就是员工表了,就
补充1: 登陆之后显示用户名字,在页面用<@shiro.principal/>就可以获得当强登陆用户名,当然也可以用${username}单这个是用了controller返回的对象的mv.addObject(“username”, username);推荐用<@shiro.principal/>
- springmvc+spring+mybatis+shrio+mysql
- 基于Spring、SpringMVC、MyBatis、Druid、Shrio构建web系统
- MySql三表联查(Spring+SpringMVC+MyBatis)
- Spring+SpringMVC+Mybatis+Mysql整合实例
- Spring+SpringMVC+Mybatis+Mysql整合实例
- Spring+Mybatis+SpringMVC+Maven+MySql搭建实例
- SpringMVC+Spring+Mybatis+Mysql项目搭建
- maven整合spring+springMvc+Mybatis+Mysql
- Spring+Mybatis+SpringMVC+Maven+MySql搭建实例
- Spring+Mybatis+SpringMVC+Maven+MySql搭建实例
- Spring+Mybatis+SpringMVC+Maven+MySql搭建实例
- Spring+SpringMVC+Mybatis+Mysql整合实例
- Spring+Mybatis+SpringMVC+Maven+MySql搭建实例
- Spring+Mybatis+SpringMVC+Maven+MySql搭建实例
- Spring+Mybatis+SpringMVC+Maven+MySql搭建实例
- Spring+SpringMVC+MyBatis+MySql框架整合实例
- spring+SpringMVC+Maven+Mybatis+Mysql分页实现
- Spring+SpringMVC+Mybatis+Mysql整合实例
- Android ConstraintLayout使用指南
- 深入理解Java虚拟机(二)
- CentOS7安装MySQL5.7
- ETH与以太坊代币钱包MyEtherWallet使用教程
- inout的具体使用方法
- springmvc+spring+mybatis+shrio+mysql
- bzoj2245: [SDOI2011]工作安排
- 搬家
- 9.10沈阳站网赛补题
- cctype中的字符函数
- 在某些情况下,实参与引用参数不匹配,C++将生成临时变量
- 何时使用引用参数
- 程序编译原理小析
- 解决Eclipse无法正常编译的问题