1. 程式人生 > >spring-shiro(三)-- spring boot + mybatis +shrio+spring mvc

spring-shiro(三)-- spring boot + mybatis +shrio+spring mvc

前面對shiro記性了一些邏輯的操作,和具體的程式碼片段的操作,現在將我寫的一個小的案例,總結一下。總結完明天就上班了。

本案例使用的是spring boot + spring mvc +mybatis

專案的結構

首先對pom檔案進行操作

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

    <groupId>com.sgqing</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--用於進行資料連線的-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!--spring提供的模板檔案-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>net.sourceforge.nekohtml</groupId>
            <artifactId>nekohtml</artifactId>
            <version>1.9.22</version>
        </dependency>
        <!--包含spring mvc等web操作-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--shiro包-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>
        <!--用的是mysql的資料庫-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-devtools</artifactId>
              <optional>true</optional>
          </dependency>-->
        <!--spring  boot-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.0</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.0</version>
        </dependency>


    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

下面對application.yml進行配置

<!--對資料庫進行配置-->
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
<!--對tomcat進行設定啟動的埠-->
server:
  port: 9992

<!--對mybatis進行設定-->
mybatis:
  typeAliasesPackage: com.sgqing.demo.dao
  mapperLocations: classpath:mapper/*.xml

下面對shiro的核心兩個類進行操作,這兩個類分別代表的是認證和授權

package com.sgqing.demo.comfig;


import com.sgqing.demo.entity.SysPermission;
import com.sgqing.demo.entity.SysRole;
import com.sgqing.demo.entity.UserInfo;
import com.sgqing.demo.sevice.UserInfoService;
import org.apache.coyote.http2.ByteUtil;
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.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

public class MyShiroRealm extends AuthorizingRealm {

    @Autowired
    private UserInfoService userInfoService;

    /**
     * 進行授權
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//        進行獲取使用者資訊
        UserInfo info = (UserInfo) principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//對使用者和角色進行分別的獲取,然後新增到SimpleAuthorizationInfo返回
        for (SysRole role : info.getRoleList()) {
//            將角色放到SimpleAuthorizationInfo中
            authorizationInfo.addRole(role.getRole());
            for (SysPermission permission : role.getPermissions()) {
                authorizationInfo.addStringPermission(permission.getPermission());
            }
        }
        return authorizationInfo;
    }

    /**
     * 進行認證
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

//        首先獲取頁面傳遞過來的資料 -- 使用者名稱
        String name = (String) authenticationToken.getPrincipal();
        System.out.println(authenticationToken.getCredentials());
        UserInfo byUsername = userInfoService.findByUsername(name);
        System.out.println(" ByteSource.Util.bytes(byUsername.getCredentialsSalt()):" + ByteSource.Util.bytes(byUsername.getCredentialsSalt()));
//         ByteSource.Util.bytes(byUsername.getCredentialsSalt()), 對密碼進行加密操作,該引數是 鹽  md5
        SimpleAuthenticationInfo authenticationInfo =
                new SimpleAuthenticationInfo(
                        name,
                        byUsername.getPassword(),
                        ByteSource.Util.bytes(byUsername.getCredentialsSalt()),
                        getName()
                );
        return authenticationInfo;
    }
}

使用類的配置

package com.sgqing.demo.comfig;

import com.sgqing.demo.Except.MyExceptionResolver;
import org.aopalliance.aop.Advice;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

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

/**
 * Shiro的配置
 */
@Configuration
public class ShiroConfig {

    /**
     * 該bena是當用戶訪問某個許可權的時候,如果沒有指定的許可權進行跳轉的頁面
     *
     * @return
     */
    @Bean
    public MyExceptionResolver myExceptionResolver() {
        MyExceptionResolver resolver = new MyExceptionResolver();
        return resolver;
    }

    /**
     * 因為在密碼返回的時候,我們加了鹽,所以需要進行解密
     * @return
     */
    @Bean
    public HashedCredentialsMatcher credentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();

        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        hashedCredentialsMatcher.setHashIterations(2);//相當於md5(md5(""))
        return hashedCredentialsMatcher;
    }

    @Bean
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
//        因為在使用的時候設定了md5進行密碼的加密,所以需要進行解密
        myShiroRealm.setCredentialsMatcher(credentialsMatcher());
        return myShiroRealm;
    }


    //設定SecurityManager
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager defaultWebSecurityManager =
                new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(myShiroRealm());
        return defaultWebSecurityManager;
    }


    //首先設定shiro的工廠類
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
// 進行攔截器的設定

        Map<String, String> filterMap = new HashMap<>();
        filterMap.put("/static/**", "anon");
        filterMap.put("/logout", "logout");
        filterMap.put("/**", "authc");

        shiroFilterFactoryBean.setLoginUrl("/login");

        shiroFilterFactoryBean.setSuccessUrl("/index");
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactoryBean;
    }

    //    開啟shiro的註解  開啟代理
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    /**
     * 異常處理
     *
     * @return
     */
    @Bean
    public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
        SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
        Properties properties = new Properties();
        properties.setProperty("DatabaseException", "databaseError");//資料庫異常處理
        properties.setProperty("UnauthorizedException", "403");
        resolver.setExceptionMappings(properties);
        resolver.setDefaultErrorView("error");    // No default
        resolver.setExceptionAttribute("ex");     // Default is "exception"
        return resolver;
    }

}



配置的當沒有許可權的時候,跳轉的頁面

package com.sgqing.demo.Except;

import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 用於設定當沒有訪問許可權的時候,用於跳轉指定的頁面,用到ModelAndView來進行設定頁面的跳轉
 */
public class MyExceptionResolver implements HandlerExceptionResolver {


    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception ex) {
        // TODO Auto-generated method stub
        System.out.println("==============異常開始=============");
        //如果是shiro無權操作,因為shiro 在操作auno等一部分不進行轉發至無許可權url
        if (ex instanceof UnauthorizedException) {
            ModelAndView mv = new ModelAndView("/403");
            return mv;
        }
        ex.printStackTrace();
        System.out.println("==============異常結束=============");
        ModelAndView mv = new ModelAndView("/403");
        return mv;
    }
}

這是程式碼中一些重要的程式碼片段,如果有需要程式碼的,可以下載我們的案例,在案例中沒有提供資料庫的檢表語句,需要自己手動建立庫和表:https://gitee.com/sgqing/spring-boot--springmvc--shiro.git