shiro框架与ssm集成

shiro框架整合ssm

  1. 组成部分:Spring + SpringMVC + Mybatis + shiro;

  2. 本教程的使用环境为Java8, IDEA 以及 Maven;

  3. 开始教程

    1. 搭建SSM教程详见https://blog.csdn.net/weixin_51717204/article/details/119180393?spm=1001.2014.3001.5501

    2. 在pom.xml文件中写入以下代码:

      <!-- shiro  -->
          <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-all</artifactId>
            <version>1.3.2</version>
          </dependency>
          <!-- 引入ehcache的依赖,给shiro做缓存权限用的 -->
          <!--<dependency>
              <groupId>net.sf.ehcache</groupId>
              <artifactId>ehcache</artifactId>
              <version>2.10.6</version>
          </dependency>-->
          <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.12</version>
          </dependency>
      
    3. 在applicationContext.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: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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
          <context:component-scan base-package="cn.kgc"/>
      
          <context:property-placeholder location="classpath*:db.properties"/>
      
          <bean class="com.mchange.v2.c3p0.DriverManagerDataSource" id="dataSource">
              <property name="jdbcUrl" value="${jdbc.url}"/>
              <property name="driverClass" value="${jdbc.driver}"/>
              <property name="password" value="${jdbc.password}"/>
              <property name="user" value="${jdbc.username}"/>
          </bean>
          <bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sessionFactory">
              <property name="dataSource" ref="dataSource"/>
              <property name="mapperLocations" value="classpath*:/mappers/*Mapper.xml"/>
          </bean>
          <!--扫描dao层-->
          <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" id="configurer">
              <property name="basePackage" value="cn.kgc.dao"/>
          </bean>
      
          <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="dataSourceTransactionManager">
              <property name="dataSource" ref="dataSource"/>
          </bean>
      
          <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
              <property name="testOnBorrow" value="true"/>
              <property name="maxTotal" value="100"/>
              <property name="maxIdle" value="8"/>
          </bean>
          <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
              <constructor-arg name="host" value="127.0.0.1"/>
              <constructor-arg name="port" value="6379"/>
              <constructor-arg name="poolConfig" ref="jedisPoolConfig"/>
          </bean>
      
          <!-- 配置 shiro 的核心组件:securityManager -->
          <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
              <!-- 配置缓存 -->
              <property name="rememberMeManager" ref="rememberMeManager"/>
              <!-- 配置域realm,用户名,密码,角色都保存在域里:实现从数据库中获取用户信息,需要我们自己创建一个类(实现Realm接口) -->
              <property name="realm" ref="shiroRealm"/>
          </bean>
      
          <!-- 配置自己域realm实现  -->
          <bean id="shiroRealm" class="cn.kgc.service.shiro.UserRealm">
              <property name="credentialsMatcher">
                  <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                      <property name="hashAlgorithmName" value="MD5"></property>
                      <property name="hashIterations" value="3"></property>
                  </bean>
              </property>
          </bean>
      
          <!-- 配置shiro的一些拦截规则,id必须和web.xml中的 shiro 拦截器名一致 -->
          <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
              <!-- Shiro的核心安全接口,这个属性是必须的 -->
              <property name="securityManager" ref="securityManager"/>
              <!-- 身份认证失败,则跳转到登录页面的配置 -->
              <property name="loginUrl" value="/user/gotologin"/>
              <!-- 登录成功后的页面 -->
              <property name="successUrl" value="/admin/index"/>
              <!-- 权限认证失败,则跳转到指定页面 -->
              <property name="unauthorizedUrl" value="/unauthorized"/>  <!-- 登录后访问没有权限的页面后跳转的页面 -->
              <!-- Shiro连接约束配置,即过滤链的定义 -->
              <property name="filterChainDefinitions">
                  <value>
                      <!-- 注意:规则是有顺序的,从上到下,拦截范围必须是从小到大的 -->
                      <!--  url = 拦截规则(anon为匿名,authc为要登录后,才能访问,logout登出过滤) -->
                      /logins/login = anon
                      /logout = anon
                      /user/gotologin = anon
                      /logins/admin = authc,permissionFilter,roles[admin]
                      /user/** = authc
                  </value>
              </property>
              <!-- 用户自定义的过滤器 -->
              <property name="filters">
                  <map>
                      <entry key="permissionFilter" value-ref="userAccessControlFilter"/>
                  </map>
              </property>
          </bean>
      
          <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
      
          <!-- 会话Cookie模板 -->
          <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
              <constructor-arg value="sid"/>
              <property name="httpOnly" value="true"/>
              <!--maxAge=-1表示浏览器关闭时失效此Cookie -->
              <property name="maxAge" value="-1"/>
          </bean>
          <!-- rememberMeCookie:即记住我的Cookie,保存时长30天 -->
          <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
              <constructor-arg value="rememberMe"/>
              <property name="httpOnly" value="true"/>
              <property name="maxAge" value="2592000"/><!-- 30天 -->
          </bean>
      
          <!-- rememberMe管理器 -->
          <bean id="rememberMeManager"
                class="org.apache.shiro.web.mgt.CookieRememberMeManager">
              <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).
                                                    decode('4AvVhmFLUs0KTA3Kprsdag==')}"/>
              <property name="cookie" ref="rememberMeCookie"/>
          </bean>
      
      </beans>
      
    4. 在applicationContext-Mvc.xml配置文件中写入以下代码:

      <!-- 开启Shiro注解 -->
      	<aop:config proxy-target-class="true"></aop:config>
      	<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
      		<property name="securityManager" ref="securityManager"/>
      	</bean>
      
    5. 在web.xml中写入以下代码:

       <!--spring 整合安全框架-->
          <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>
      
    6. 需要继承 AuthorizingRealm 类,并重写doGetAuthenticationInfo和doGetAuthorizationInfo方法

      • doGetAuthenticationInfo :该方法主要用于登录验证;

        @Override
            protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
                UsernamePasswordToken token1 = (UsernamePasswordToken) token;
                String username = token1.getUsername();
                User user = userService.queryUserByUserCode(username);
                System.out.println(">>>>>" + user);
                if (user == null){
                    System.out.println(">>>>>user为null");
                    throw new UnknownAccountException("用户名或密码错误!");
                }
                if (user .getStatus() == 0){
                    System.out.println("该用户已被禁用,请联系管理员!");
                    throw new UnknownAccountException("该用户已被禁用,请联系管理员!");
                }
                SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUserCode(),user.getUserPassword(),getName());
                authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(user.getSalt()));
                return authenticationInfo;
            }
        
      • doGetAuthorizationInfo :该方法主要用户权限认证;

        @Override
            protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
                //获取当前user的用户名
                String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
                //构造一个授权凭证
                SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
                //通过你的用户名查询数据库,得到你的权限信息与角色信息,并存放到权限凭证中
                info.addRole(getYourPermission(primaryPrincipal));
                info.addStringPermissions(getYourPermissionByUsernameFromDB(primaryPrincipal));
                final Set<String> stringPermissions = info.getStringPermissions();
                System.out.println("这是权限信息:" + stringPermissions);
                //返回你的权限信息
                return info;
            }
        
            public String getYourPermission(String username){
                final User user = userService.queryUserByUserCode(username);
                if (user.getUserRole() == 1){
                    return "admin";
                }else if (user.getUserRole() == 2){
                    return "manager";
                }else if (user.getUserRole() == 3){
                    return "staff";
                }
                return "error";
            }
        
            public List<String> getYourPermissionByUsernameFromDB(String username){
                final String yourPermission = getYourPermission(username);
                if (yourPermission.equals("admin")){
                    return Arrays.asList("code:insert","code:update","code:delete");
                }
                return Arrays.asList("code:select");
            }
        
    7. 权限认证需要自定义访问过滤器:

      package cn.kgc.vo;
      
      import javafx.beans.binding.BooleanExpression;
      import org.apache.shiro.SecurityUtils;
      import org.apache.shiro.mgt.SecurityManager;
      import org.apache.shiro.subject.Subject;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.stereotype.Component;
      
      import javax.servlet.ServletRequest;
      import javax.servlet.ServletResponse;
      import javax.servlet.http.HttpServletRequest;
      
      
      /**
       * @author hanyiming
       * @create 2021/9/2 13:16
       */
      @Component("userAccessControlFilter")
      public final class AccessControlFilter extends org.apache.shiro.web.filter.AccessControlFilter {
      
          private static final Logger LOGGER = LoggerFactory.getLogger(AccessControlFilter.class);
      
          /**
           * 是否允许访问,返回true表示允许
           * 如果返回 false ,则进入本类的onAccessDenied方法中进行处理
           * @param servletResponse
           * @param o
           * @return
           * @throws Exception
           */
          @Override
          protected boolean isAccessAllowed(ServletRequest request, ServletResponse servletResponse, Object o) throws Exception {
              final Subject subject = SecurityUtils.getSubject();
      
              //判断用户是否进行过登录认证,如果没有经过认证则返回登录页
              if (subject.getPrincipal() == null || !subject.isAuthenticated()) {
                  return Boolean.FALSE;
              }
      
              final String requestURI = this.getPathWithinApplication(request);
              if (LOGGER.isDebugEnabled()) {
                  LOGGER.debug("请求URL为:{}", requestURI);
              }
              final String requestHeader = ((HttpServletRequest) request).getHeader("Referer");
      
              //防盗链的处理
              if (requestHeader == null || "".equals(requestHeader)) {
                  return Boolean.FALSE;
              }
      
              //此处可以编写用于判断用户是否有相关权限的代码
              //subject.hasRole("需要的角色");
              //subject.isPermitted("需要的权限");
              return Boolean.TRUE;
          }
      
          @Override
          protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
      
              if (LOGGER.isDebugEnabled()) {
                  LOGGER.debug("当前账号没有相应的权限!");
              }
      
              //重定向到登录页面
              this.redirectToLogin(servletRequest, servletResponse);
              return Boolean.FALSE;
          }
      }
      
      
    8. 注册方法代码为:

      //生成盐值  ,存入数据库中
              String salt = new SecureRandomNumberGenerator().nextBytes().toHex();
              //将原始密码加盐,并且使用MD5算法加密一次,将最后结果存入数据库
      	    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!注意此处加密方式与加密次数应与 applicationContext.xml配置文件中相同
              String result = new Md5Hash(user.getUserPassword(),salt,1).toString();
              user.setUserPassword(result);
              user.setSalt(salt);
              Integer integer = userMapper.addUser(user);
              log.info("<<<<<<<<<<<<<<<< 与用户添加完成,受影响行数:" + integer);
      
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值