博客详情

springshiro(1.5.17)+redis (原创)

作者: 朝如青丝暮成雪
发布时间:2019-06-15 03:21:07  文章分类:java编程   阅读(864)  评论(0)
[TOC]

一、springshiro(1.5.17)+redis整合

基于springboot-1.5.17构建,packaging选择war方式

1.pom.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.17.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.tingcream</groupId>
    <artifactId>springshiro</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>springshiro</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- 引入jsp 、jstl支持  -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency> 


           <!-- 配置aop支持的方式二 spring的织入  aspects  cglib  -->
        <dependency>
          <groupId>org.springframework</groupId>
           <artifactId>spring-aspects</artifactId>
           <!-- <version>4.3.20.RELEASE</version> -->
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib-nodep</artifactId>
            <version>3.2.0</version>
        </dependency>  

        <!-- jdbc starter引入 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>  
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!-- 引入druid连接池  -->  
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>  

        <!-- 引入mybatis的starter  -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>


        <!-- redis的starter引入 -->
         <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-data-redis</artifactId>
         </dependency>


        <!-- shiro spring 引入 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>



    </dependencies>


  <build>
        <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
             <include>**/*</include>
            </includes>
            <excludes>
               <exclude>**/*.java</exclude>
            </excludes>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*</include>
            </includes>
            <excludes>
              <exclude>**/*.java</exclude>
            </excludes>
        </resource>
    </resources>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
         <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-compiler-plugin</artifactId>
             <configuration>
                <target>1.8</target>   
                <source>1.8</source>
                <encoding>utf-8</encoding>
             </configuration>
          </plugin>
    </plugins>
</build>

</project>

pom.xml中shiro-spring-1.4.0会自动引入shiro-web-1.4.0.jar,shiro-web-1.4.0.jar会自动引入shiro-core-1.4.0jar。故这里整合时,shiro的依赖包我们只需要引入一个shiro-spring-1.4.0jar即可。

2.application.yml配置

#服务器配置 
server: 
  port: 8082
  context-path: /

spring: 
  #devtools配置
  devtools:
    restart:
      exclude: static/**
  application:
    name: springshiro
 #jsp视图  
  mvc: 
    view:
      prefix: /WEB-INF/pages
      #suffix: .jsp

  #数据库连接池       
  datasource:
    druid:
      driver-class-name: com.mysql.jdbc.Driver
      username: root
      password: 123456
      url: jdbc:mysql://localhost:3306/springshiro?useUnicode=true&characterEncoding=utf-8&useSSL=false 
      initial-size: 5 #初始化连接数
      max-active: 10  #最大活跃连接数
      min-idle: 5 #最小空闲连接数
      max-wait: 60000 #最大连接等待时间 毫秒
      remove-abandoned: true #超过时间限制是否回收
      removeAbandonedTimeout: 1800 #超时丢弃连接 1800秒即30分钟
      timeBetweenEvictionRunsMillis: 60000 #配置时间间隔进行一次检测,毫秒
      validationQuery: SELECT 1 FROM DUAL #用来检测连接是否有效的sql,要求是一个查询语句 
      testWhileIdle: true  #申请连接的时候检测
      testOnBorrow: false
      testOnReturn: false
      poolPreparedStatements: true #打开PSCache,并且指定每个连接上PSCache的大小
      maxPoolPreparedStatementPerConnectionSize: 20
      maxOpenPreparedStatements: 20
  #redis连接池    
  redis:
    host: 192.168.11.10
    port: 6379
    password: 123456
    ssl: false
    database: 1
    timeout: 6000
    jedis: 
      pool:
        max-active: 8 #缺省值8
        max-idle: 8 #缺省值8
        min-idle: 0 #缺省值0
        max-wait: 3000 #缺省值-1  

mybatis:
  config-location: classpath:SqlMapConfig.xml


#日志
logging: 
  level: 
    root: INFO
    org.springframework.web: INFO
    org.springframework.jdbc: DEBUG
    com.tingcream.springshiro: DEBUG
  file: e:/log/springshiro/springshiro.log

3.SqlMapConfig.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <settings>
    <!-- 启动延迟加载  积极加载false -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
  </settings>

   <typeAliases>
     <!--   <package name="com.tingcream.springmybatis.model"/> -->
     <!-- 配置实体bean包及其子包,别名为类名的简单名称,首字母大小写均可。如Student或student均可 -->
       <package name="com.tingcream.springshiro"/>  
   </typeAliases>

    <mappers>
    <!--配置mapper接口和mapper.xml所在包(包含子包)-->
      <package name="com.tingcream.springshiro"/>
    </mappers>

</configuration>

4.SpringshiroApplication启动类

package com.tingcream.springshiro;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication
@EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true) 
@MapperScan(basePackages= {"com.tingcream.springshiro"})//可多个,含子包,支持通配符
public class SpringshiroApplication   extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(SpringshiroApplication.class, args);
    }
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(SpringshiroApplication.class);
    }
}

二、Redis配置

1.RedisConfig配置类

package com.tingcream.springshiro.configuration;

import java.io.Serializable;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.tingcream.springshiro.common.redis.RedisHelper;

@Configuration
public class RedisConfig {

    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Bean
    public RedisTemplate<Serializable, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate redisTemplate = new RedisTemplate();
        StringRedisSerializer keySerializer = new StringRedisSerializer();
        GenericJackson2JsonRedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer();
        redisTemplate.setConnectionFactory(connectionFactory);
        redisTemplate.setKeySerializer(keySerializer);//键
        redisTemplate.setHashKeySerializer(keySerializer);//键
        redisTemplate.setValueSerializer(valueSerializer);//值
        redisTemplate.setHashValueSerializer(valueSerializer);//值

        return redisTemplate;
    }

    @Bean
    public RedisHelper redisHelper(RedisTemplate<Serializable, Object> redisTemplate) {
        RedisHelper redisHelper = new RedisHelper();
        redisHelper.setRedisTemplate(redisTemplate);
        return redisHelper;
    }
}

2.RedisHelper.java

package com.tingcream.springshiro.common.redis;

import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

/**  
* redis 辅助工具类
* @author jelly
*/
public class RedisHelper {

      private RedisTemplate<Serializable, Object> redisTemplate; 
      public void setRedisTemplate(  RedisTemplate<Serializable, Object> redisTemplate) { 
        this.redisTemplate = redisTemplate; 
      } 
      public RedisTemplate<Serializable, Object> getRedisTemplate() {
        return redisTemplate;
      }

      /**
       * hash set
       * @param key
       * @param field
       * @param value
       */
      public  void     hset(String key ,String field,Object value){
            BoundHashOperations<Serializable, String, Object> hashOperation=  redisTemplate.boundHashOps(key);
            hashOperation.put(field, value);
      }    
      /**
       * hash  set  with ttlSec
       * @param key
       * @param field
       * @param value
       * @param ttl
       */
      public   void   hset(String key ,String field,Object value,long ttl){
            BoundHashOperations<Serializable, String, Object> hashOperation=  redisTemplate.boundHashOps(key);
            hashOperation.put(field, value);
            redisTemplate.expire(key, ttl, TimeUnit.SECONDS);
      }

      /**
       * hash  get
       * @param key
       * @param field
       * @return
       */
      public  Object   hget(String key,String field){
          BoundHashOperations<Serializable, String, Object> hashOperation=  redisTemplate.boundHashOps(key);
          return   hashOperation.get(field);
      }
      /**
       * hash  hdel  field
       * @param key
       * @param field
       */
      public  void hdel(String key,Object field){
          BoundHashOperations<Serializable, String, Object> hashOperation=  redisTemplate.boundHashOps(key);
           hashOperation.delete(field);
      }
      /**
       * hash  hdel  field1  field2
       * @param key
       * @param fields
       */
      public  void hdel(final String key,final Object... fields){
          BoundHashOperations<Serializable, String, Object> hashOperation=  redisTemplate.boundHashOps(key);
          hashOperation.delete(fields);
      }

      /**
       * hash hlen
       * @param key
       * @return
       */
      public  Long    hlen(String key){
          BoundHashOperations<Serializable, String, Object> hashOperation=  redisTemplate.boundHashOps(key);
         return  hashOperation.size();
      }
      /**
       * hash  hkeys
       * @author jelly
       * @param key
       * @return
       */
      public  Set<String> hkeys(String key){
          BoundHashOperations<Serializable, String, Object> hashOperation=  redisTemplate.boundHashOps(key);
         return  hashOperation.keys();
      }
      /**
       * hash hvals
       * @param key
       * @return
       */
      public   List<Object> hvals(String key){
            BoundHashOperations<Serializable, String, Object> hashOperation=  redisTemplate.boundHashOps(key);
             return  hashOperation.values();
      }
      /**
       * hash  hgetall
       * @param key
       * @return
       */
      public   Map<String,Object> hgetall(String key){
               BoundHashOperations<Serializable, String, Object> hashOperation=  redisTemplate.boundHashOps(key);
             return  hashOperation.entries();
      }

      /**
       * 传入 多个key   
       * key1 key2 key3
       */
      public void remove(final String... keys) { 

        for (String key : keys) { 
          remove(key); 
        } 
      } 
      /** 
       * 批量删除key  根据匹配的parttern   
       * 如 mylist*   能匹配 mylist1 mylist2  
       */
      public void removePattern(final String pattern) { 
        Set<Serializable> keys = redisTemplate.keys(pattern); 
        if (keys.size() > 0) {
            redisTemplate.delete(keys);
        }

      } 

      /**
       * 删除key-Object  根据传入的key
       */
      public void remove(final String key) { 
          redisTemplate.delete(key); 
      } 

      /**
       * 判断缓存中是否存在 指定的key
       */
      public boolean exists(final String key) { 
        return redisTemplate.hasKey(key); 
      } 

      /** 
       * 读取缓存 
       * @param key 
       * @return 
       */
      public Object get(final String key) { 
        Object result = null; 
        ValueOperations<Serializable, Object> operations = redisTemplate .opsForValue(); 
        result = operations.get(key); 
        return result; 
      } 

      /**
       * set 
       * @author jelly
       * @param key
       * @param value
       */
      public void set(final String key, Object value) { 
        try { 
          ValueOperations<Serializable, Object> operations = redisTemplate .opsForValue(); 
          operations.set(key, value); 
        } catch (Exception e) { 
           e.printStackTrace();
        } 
      } 

      /**
       * set 
       * @param key
       * @param value
       * @param ttl
       */
      public void set(final String key, Object value, Long ttl) { 
          ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); 
          operations.set(key, value, ttl, TimeUnit.SECONDS) ;
          redisTemplate.expire(key, ttl, TimeUnit.SECONDS);//
      } 
      public boolean expireKey(final String key, Long ttl){
          return  redisTemplate.expire(key, ttl, TimeUnit.SECONDS);
      }

      /**
       * 清空redis当前db
       */
      public void flushDB(){
          redisTemplate.execute(new RedisCallback<String>() {

                @Override
                public String doInRedis(RedisConnection connection)
                        throws DataAccessException {
                    try {
                        connection.flushDb();
                        return "";
                    } catch (Exception e) {
                        e.printStackTrace();
                        throw new RuntimeException(e);
                    }
                }

            });
      }
      /**
       * 清空redis所有 db
       */
      public void flushAll(){
          redisTemplate.execute(new RedisCallback<String>() {

                @Override
                public String doInRedis(RedisConnection connection)
                        throws DataAccessException {
                    try {
                        connection.flushAll();
                        return "";
                    } catch (Exception e) {
                        e.printStackTrace();
                        throw new RuntimeException(e);
                    }
                }

        });
      }
}

三、Shiro配置

1.pom.xml中引入shiro-spring

<!-- shiro spring 引入 -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0</version>
</dependency>

2.ShiroConfig配置类

package com.tingcream.springshiro.configuration;

import java.util.HashMap;
import java.util.Map;

import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.filter.DelegatingFilterProxy;

import com.tingcream.springshiro.shiro.MyRealm;

/**
 * shiro 配置类
 * @author jelly
 */
@Configuration
public class ShiroConfig {

        @Bean(name = "lifecycleBeanPostProcessor")
        public   LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
            return new LifecycleBeanPostProcessor();
        }
        @Bean
        @DependsOn({ "lifecycleBeanPostProcessor" })
        public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
            DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
            autoProxyCreator.setProxyTargetClass(true);//aop切入  
            return autoProxyCreator;
        }


        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
                DefaultWebSecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor advisor = 
                    new AuthorizationAttributeSourceAdvisor();
            advisor.setSecurityManager(securityManager);
            return advisor;
        }

        //将自己的验证方式加入容器
        @Bean
        public MyRealm myRealm() {
           return new MyRealm();
        }


        //配置shiro session 的一个管理器
        @Bean(name = "sessionManager")
        public DefaultWebSessionManager sessionManager(){
            DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
            // 设置session过期时间
            sessionManager.setGlobalSessionTimeout(30*60*1000);
            return sessionManager;
        }

        @Bean(name = "securityManager")
        public DefaultWebSecurityManager   securityManager() {
            DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
            defaultWebSecurityManager.setRealm( myRealm() );
            defaultWebSecurityManager.setSessionManager( sessionManager() );
            return defaultWebSecurityManager;
        }



        @Bean
        public FilterRegistrationBean<DelegatingFilterProxy> delegatingFilterProxy(){
            FilterRegistrationBean<DelegatingFilterProxy> filterRegistrationBean = new FilterRegistrationBean<DelegatingFilterProxy>();
            DelegatingFilterProxy proxy = new DelegatingFilterProxy();
            proxy.setTargetFilterLifecycle(true);
            proxy.setTargetBeanName("shiroFilter");
            filterRegistrationBean.setFilter(proxy);
            filterRegistrationBean.setOrder(1);
            //filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST);
            filterRegistrationBean.addUrlPatterns("/*");

            return filterRegistrationBean;
        }



        //Filter工厂,设置对应的过滤条件和跳转条件
        @Bean("shiroFilter")
        public ShiroFilterFactoryBean shiroFilterFactoryBean() {
             ShiroFilterFactoryBean filterBean =new ShiroFilterFactoryBean();
               filterBean.setSecurityManager(securityManager());//shiro的核心安全接口,这个属性是必须的
               filterBean.setLoginUrl("/login");//身份认证失败,跳转到登陆页面url
               filterBean.setSuccessUrl("/home");//登录成功 跳转的页面url
               filterBean.setUnauthorizedUrl("/unauthorized");//权限验证失败,跳转到指定页面url
              //Map<String, Filter> filters=new HashMap<String,Filter>();
              //filterBean.setFilters(filters);
              Map<String,String>   filterChainDefinitionMap =new HashMap<String,String>();
              filterChainDefinitionMap.put("/static/**", "anon");
              filterChainDefinitionMap.put("/login", "anon");    
              filterChainDefinitionMap.put("/logout", "logout");  
             // filterChainDefinitionMap.put("/student/**", "roles[student]");
             // filterChainDefinitionMap.put("/teacher/**", "roles[teacher]");
              filterChainDefinitionMap.put("/**", "authc");

               filterBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
               return filterBean ;
        }

}

3.MyRealm.java

package com.tingcream.springshiro.shiro;

import java.util.Set;

import org.apache.shiro.SecurityUtils;
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.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import com.tingcream.springshiro.user.model.User;
import com.tingcream.springshiro.user.service.LoginService;

/**
 * 自定义 realm
 */
public class MyRealm extends AuthorizingRealm {

    @Autowired
    private  LoginService loginService ;


    @Override
    public String getName() {
        return "myRealm";
    }

    /**
     * 对当前subject进行身份认证
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("访问了doGetAuthenticationInfo认证方法");
        String username=(String)token.getPrincipal();
        User user =loginService.findUserByUsername(username);
        if(user==null) {
            //登陆失败
            return null;
        }
        AuthenticationInfo authcInfo=new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),getName());
        return authcInfo;

    }

    /**
     * 对当前subject进行权限认证(授权)
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("访问了doGetAuthorizationInfo授权方法");
         String username=(String)principals.getPrimaryPrincipal();
        SecurityUtils.getSubject().getSession();
        SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
        Set<String> roleNames=loginService.findUserRoleNames(username);
        Set<String> permNames=loginService.findUserPermNames(username);
        authorizationInfo.setRoles(roleNames);
        authorizationInfo.setStringPermissions(permNames);
        return authorizationInfo;

    }

}

4.GlobalExceptionHandler

package com.tingcream.springshiro.common.exception;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.tingcream.springshiro.common.ret.RetMsg;

@ControllerAdvice
public class GlobalExceptionHandler {
    private Logger logger =LoggerFactory.getLogger(this.getClass());

    @ResponseBody
    @ExceptionHandler(BindException.class)
    public RetMsg  handleBindException(BindException e,HttpServletRequest request) {
        logger.error(e.getMessage(),e);//记录完整错误信息
        Map<String,String> map=new HashMap<String,String>();
        List<ObjectError> errors = e.getBindingResult().getAllErrors();
        errors.stream().forEach((ObjectError err)->{
            String field= ((FieldError)err).getField();
            String msg =err.getDefaultMessage();
            map.put(field,msg);
        });
        return new RetMsg(999, "请求参数验证失败", map);
    }

//    /**
//     * shiro 授权验证不通过 
//     * @return
//     */
//    @ResponseBody
//    @ExceptionHandler(value=UnauthorizedException.class)
//    public RetMsg handleUnauthorizedException(UnauthorizedException e,HttpServletRequest request) {
//        logger.error(e.getMessage(),e);
//        System.out.println("shiro授权验证不通过");
//        return RetMsg.success("抱歉,授权验证不通过,您无法访问此资源");
//    }
    /**
     * shiro 授权验证不通过 
     * @return
     */
    @ExceptionHandler(value=UnauthorizedException.class)
    public ModelAndView  handleUnauthorizedException(UnauthorizedException e,HttpServletRequest request) {
        logger.error(e.getMessage(),e);
        System.out.println("shiro授权验证不通过");
        return new ModelAndView("/unauthorized.jsp");//返回jsp视图
    }

}

四、用户登录(认证)

1.LoginController

package com.tingcream.springshiro.user.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class LoginController {

     @RequestMapping(value="/home",method=RequestMethod.GET)
     public String  index(HttpServletRequest request,HttpServletResponse response) {
        return "/home.jsp";
     }

     @RequestMapping(value="/login",method=RequestMethod.GET)
     public String  login(HttpServletRequest request,HttpServletResponse response) {
        return "/login.jsp";
     }

     @RequestMapping(value="/login",method=RequestMethod.POST)
     public String doLogin(HttpServletRequest request,HttpServletResponse response,
             String username,String password) {
         UsernamePasswordToken token =    new UsernamePasswordToken(username, password);
         Subject subject = SecurityUtils.getSubject();

            try{
                //注意这一步 很重要
                 subject.login(token);    
                 //subject.getSession()和request.getSession()得到的session对象的用法基本一致
                 //subject.getSession().setAttribute("currentUser", user);
                 subject.getSession().setAttribute("msg", "你好,您已登录成功!");
                // return "forward:/home";
                 return "redirect:/home";//重定向到首页
              }catch  ( UnknownAccountException e ) { 
                     e.printStackTrace();
                     System.out.println("未知的账户,用户名不存在");
                } catch  ( IncorrectCredentialsException e ) {
                     e.printStackTrace();
                     System.out.println("密码错误");
                } catch  ( LockedAccountException e ) { 
                      e.printStackTrace();
                     System.out.println("账户被锁定");

                } catch  ( ExcessiveAttemptsException e ) { 
                      e.printStackTrace();
                      System.out.println("过度的尝试");

                }catch ( AuthenticationException e ) {
                      e.printStackTrace();
                      System.out.println("认证失败");
                }catch(Exception e) {
                    e.printStackTrace();
                }
             request.setAttribute("errMsg", "用户名或者密码错误");
             return  "/login.jsp";
     }

     @RequestMapping("/unauthorized")
     public String  unauthorized() {
         return "/unauthorized.jsp";
     }
}

home.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
<h1>home 首页 </h1>
 ${msg} ==== 欢迎您 :<shiro:principal /> <br/>
 用户id: ${sessionUser.userId }  <br/>
 用户创建时间:  ${sessionUser.createtime } 
</body>
</html>

login.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
<h1>用户登录</h1>
 <form action="${pageContext.request.contextPath }/login" method="post">
   username: <input type="text" name="username"/> <br/>
   password: <input type="password" name="password"/> <br/>
  <button type="submit">登录</button>  ${errMsg}
 </form>
</body>
</html>

unauthorized.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
<h1>unauthorized</h1>
 <h3>抱歉,权限(role、perms)验证未通过</h3>
</body>
</html>

student.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
<h1>student.jsp页面</h1>
</body>
</html>

teacher.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
<h1>teacher.jsp页面</h1>
</body>
</html>

2.LoginService

package com.tingcream.springshiro.user.service;

import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.tingcream.springshiro.common.constant.GlobalConstant;
import com.tingcream.springshiro.common.redis.RedisHelper;
import com.tingcream.springshiro.user.mapper.UserMapper;
import com.tingcream.springshiro.user.model.User;

@Service
//@Transactional
public class LoginService {

    @Autowired
    private UserMapper userMapper ;

    @Autowired
    private RedisHelper redisHelper ;

    /**
     * 根据用户名查询用户实体
     * @param username 用户名
     * @return
     */
    public  User findUserByUsername(String username) {
          User user = (User) redisHelper.hget(GlobalConstant.CACHE_USER, username);
          if(user==null) {
             user= userMapper.findUserByUsername(username);
             redisHelper.hset(GlobalConstant.CACHE_USER, username, user); 
          }
        return user;
    }
    /**
     * 根据用户id查询用户所有的角色名称
     * @param username 用户名
     * @return
     */


    @SuppressWarnings("unchecked")
    public Set<String> findUserRoleNames(String username ){
        Set<String> names= (Set<String>) redisHelper.hget(GlobalConstant.CACHE_USER_ROLENAMES,username);   
        if(names==null) {
            names=userMapper.findUserRoleNames(username);
            redisHelper.hset(GlobalConstant.CACHE_USER_ROLENAMES, username, names);
        }
        return names;
    }

    /**
     * 根据用户id查询用户所有的权限名称 
     * @param username 用户名
     * @return
     */
    @SuppressWarnings("unchecked")
    public Set<String> findUserPermNames(String username){
        Set<String> names= (Set<String>) redisHelper.hget(GlobalConstant.CACHE_USER_PERMNAMES,username);   
        if(names==null) {
            names=userMapper.findUserPermNames(username);
            redisHelper.hset(GlobalConstant.CACHE_USER_PERMNAMES, username, names);
        }
        return names;
    }
}

GlobalConstant.java

package com.tingcream.springshiro.common.constant;

public class GlobalConstant {

    public static final String SESSION_USER="sessionUser";

    //缓存对象hash key是user field为username变量  value为user对象 
    public static final String CACHE_USER="user";

    //缓存对象hash  key为user_roleNames field为username变量  value为names List<String>
    public static final String CACHE_USER_ROLENAMES="user_roleNames";

    //缓存对象hash  key为user_permNames field为username变量  value为names List<String>
    public static final String CACHE_USER_PERMNAMES="user_permNames";
}

3.UserMapper

UserMapper.java

package com.tingcream.springshiro.user.mapper;

import java.util.Set;
import com.tingcream.springshiro.user.model.User;

public interface UserMapper {      

    /**
     * 根据用户名查询用户实体
     * @param username 用户名
     * @return
     */
    public  User findUserByUsername(String username);

    /**
     * 根据用户id查询用户所有的角色名称
     * @param username 用户名
     * @return
     */
    public Set<String> findUserRoleNames(String username );

    /**
     * 根据用户id查询用户所有的权限名称 
     * @param username 用户名
     * @return
     */
    public Set<String> findUserPermNames(String username);

  }

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper 
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.tingcream.springshiro.user.mapper.UserMapper"> 

      <!-- 根据用户名查询用户实体 -->
     <select id="findUserByUsername" parameterType="string" resultType="User">
       select * from t_user t where t.username =#{_parameter}
     </select>

     <!-- 根据用户id查询用户所有的角色名称 -->
     <select id="findUserRoleNames" parameterType="string" resultType="string">
       SELECT c.`roleName` FROM  t_user a
        JOIN  t_user_role  b ON a.`userId`=b.`userId`  
        JOIN  t_role c   ON b.`roleId`=c.`roleId`
        WHERE a.username=#{_parameter}
     </select>

     <!-- 根据用户id查询用户所有的权限名称  -->
     <select id="findUserPermNames" parameterType="string" resultType="string">
        SELECT e.`permName` FROM  t_user a
        JOIN  t_user_role  b ON a.`userId`=b.`userId`  
        JOIN  t_role c   ON b.`roleId`=c.`roleId`
        JOIN  t_role_permission d ON c.`roleId`=d.`roleId`
        JOIN  t_permission e ON d.`permId`=e.`permId`
        WHERE a.username=#{_parameter}
     </select>   
</mapper>

User.java

package com.tingcream.springshiro.user.model;

import java.io.Serializable;

/**
 * 用户实体
 * @author jelly
 */
public class User implements Serializable {

    private static final long serialVersionUID = 1L;
    private Integer userId;
    private String username;
    private String password;
    private String createtime;
    public Integer getUserId() {
        return userId;
    }
    public void setUserId(Integer userId) {
        this.userId = userId;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getCreatetime() {
        return createtime;
    }
    public void setCreatetime(String createtime) {
        this.createtime = createtime;
    }
}

五、访问授权(Student、Teacher)

StudentController

package com.tingcream.springshiro.student.controller;

import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/student")
@RequiresRoles(value="student") 
public class StudentController {

    @RequestMapping("/")
    public String  index() {
        return "/student.jsp";
    }    
}

TeacherController

package com.tingcream.springshiro.teacher.controller;

import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequiresRoles("teacher") 
@RequestMapping("/teacher")
public class TeacherController {
    @RequestMapping("/")
    public String  index() {
        return "/teacher.jsp";
    }
}

六、其他配置

数据库表

db.sql

/*
SQLyog Ultimate v12.5.0 (64 bit)
MySQL - 5.7.16 : Database - springshiro
*********************************************************************
*/

/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`springshiro` /*!40100 DEFAULT CHARACTER SET utf8 */;

/*Table structure for table `t_permission` */

DROP TABLE IF EXISTS `t_permission`;

CREATE TABLE `t_permission` (
  `permId` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `permName` varchar(50) DEFAULT NULL COMMENT '权限名称',
  `remark` varchar(50) DEFAULT NULL COMMENT '备注',
  `createtime` varchar(24) DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`permId`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;

/*Data for the table `t_permission` */

insert  into `t_permission`(`permId`,`permName`,`remark`,`createtime`) values 
(1,'student:add','学生添加','2019-03-25 13:41:18'),
(2,'student:update','学生修改','2019-03-25 13:41:21'),
(3,'student:delete','学生删除','2019-03-25 13:41:21'),
(4,'student:find','学生查询','2019-03-25 13:41:21'),
(5,'teacher:add','老师添加','2019-03-25 13:41:56'),
(6,'teacher:update','老师修改','2019-03-25 13:41:56'),
(7,'teacher:delete','老师删除','2019-03-25 13:41:56'),
(8,'teacher:find','老师查询','2019-03-25 13:41:57');

/*Table structure for table `t_role` */

DROP TABLE IF EXISTS `t_role`;

CREATE TABLE `t_role` (
  `roleId` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `roleName` varchar(32) DEFAULT NULL COMMENT '角色名称',
  `remark` varchar(50) DEFAULT NULL COMMENT '备注',
  `createtime` varchar(24) DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`roleId`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

/*Data for the table `t_role` */

insert  into `t_role`(`roleId`,`roleName`,`remark`,`createtime`) values 
(1,'student','学生','2019-03-25 13:36:31'),
(2,'teacher','老师','2019-03-25 13:36:33');

/*Table structure for table `t_role_permission` */

DROP TABLE IF EXISTS `t_role_permission`;

CREATE TABLE `t_role_permission` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `roleId` int(11) DEFAULT NULL,
  `permId` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `roleId` (`roleId`),
  KEY `permId` (`permId`),
  CONSTRAINT `t_role_permission_ibfk_1` FOREIGN KEY (`roleId`) REFERENCES `t_role` (`roleId`),
  CONSTRAINT `t_role_permission_ibfk_2` FOREIGN KEY (`permId`) REFERENCES `t_permission` (`permId`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;

/*Data for the table `t_role_permission` */

insert  into `t_role_permission`(`id`,`roleId`,`permId`) values 
(1,1,1),
(2,1,2),
(3,1,3),
(4,1,4),
(5,2,5),
(6,2,6),
(7,2,7),
(8,2,8);

/*Table structure for table `t_user` */

DROP TABLE IF EXISTS `t_user`;

CREATE TABLE `t_user` (
  `userId` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) DEFAULT NULL,
  `password` varchar(32) DEFAULT NULL,
  `createtime` varchar(24) DEFAULT NULL,
  PRIMARY KEY (`userId`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

/*Data for the table `t_user` */

insert  into `t_user`(`userId`,`username`,`password`,`createtime`) values 
(1,'zhangsan','123456','2019-03-24 13:33:34'),
(2,'lisi','123456','2019-03-24 13:33:34');

/*Table structure for table `t_user_role` */

DROP TABLE IF EXISTS `t_user_role`;

CREATE TABLE `t_user_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userId` int(11) DEFAULT NULL,
  `roleId` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `userId` (`userId`),
  KEY `roleId` (`roleId`),
  CONSTRAINT `t_user_role_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `t_user` (`userId`),
  CONSTRAINT `t_user_role_ibfk_2` FOREIGN KEY (`roleId`) REFERENCES `t_role` (`roleId`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

/*Data for the table `t_user_role` */

insert  into `t_user_role`(`id`,`userId`,`roleId`) values 
(1,1,1),
(2,2,2);

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

SpringContextAware

SpringContextAware.java (可从spring容器中手动获取bean)

package com.tingcream.springshiro.common;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringContextAware implements ApplicationContextAware {
    private static ApplicationContext applicationContext; 

    @Override 
    public void setApplicationContext(ApplicationContext applicationContext) 
            throws BeansException { 
        SpringContextAware.applicationContext = applicationContext; 
    } 

    /**
     * 获取spring容器的 applicationContext 上下文对象
     * @return
     */
    public static ApplicationContext getApplicationContext(){ 
        return applicationContext; 
    } 

    public static Object getBean(String name){ 
        return applicationContext.getBean(name); 
    } 
     /**
      * 从spring 上下文中获取bean
      * @param <T>
      * @param name
      * @param requiredClass
      * @return
      */
    public static  <T> T getBean(String name, Class<T>  requiredClass){ 
        return  applicationContext.getBean(name, requiredClass); 
    } 
    public  static  <T> T getBean(Class<T> requiredType){
     return applicationContext.getBean(requiredType);
    }
}
关键字:  springshiro
评论信息
暂无评论
发表评论

亲,您还没有登陆,暂不能评论哦! 去 登陆 | 注册

博主信息
   
数据加载中,请稍候...
文章分类
   
数据加载中,请稍候...
阅读排行
 
数据加载中,请稍候...
评论排行
 
数据加载中,请稍候...

Copyright © 叮叮声的奶酪 版权所有
备案号:鄂ICP备17018671号-1

鄂公网安备 42011102000739号