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/>

原创粉丝点击