Spring Boot 添加Shiro支持

时间:2023-11-10 17:45:38

前言:

  Shiro是一个权限、会话管理的开源Java安全框架;Spring Boot集成Shiro后可以方便的使用Session;

工程概述:

Spring Boot 添加Shiro支持

(工程结构图)

一、建立Spring Boot工程

  参照http://www.cnblogs.com/liangblog/p/5207855.html 建立一个SpringBoot工程;

二、修改pom.xml,引入所需jar包

<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.ddd</groupId>
<artifactId>programme</artifactId>
<version>0.0.1</version>
<packaging>jar</packaging> <name>programme</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.2.RELEASE</version>
</parent> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jdbc-core</artifactId>
<version>1.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency> <dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-cas</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.4.1</version>
</dependency>
</dependencies> <!-- Package as an executable jar -->
<build>
<defaultGoal>compile</defaultGoal>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> <!-- Add Spring repositories -->
<!-- (you don't need this if you are using a .RELEASE version) -->
<!--
<repositories>
<repository>
<id>spring-snapshots</id>
<url>http://repo.spring.io/snapshot</url>
<snapshots><enabled>true</enabled></snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<url>http://repo.spring.io/milestone</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<url>http://repo.spring.io/snapshot</url>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<url>http://repo.spring.io/milestone</url>
</pluginRepository>
</pluginRepositories>
--> </project>

pom.xml

  主要引入日志、数据库,shrio相关的jar包

三、添加配置文件和日志文件

配置文件需要放到resource文件夹下(指向classpath),并取名aplication.properties,工程会自动查找到文件配置信息

  配置文件:

displayname = pm

server.port=8011
server.session.timeout=1000
server.tomcat.uri-encoding=UTF-8 spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.max-idle=10
spring.datasource.max-wait=10000
spring.datasource.min-idle=5
spring.datasource.initial-size=5 logging.config=classpath:pm-logback.xml
logging.path=log

  日志文件:

<configuration scan="true" scanPeriod="10 seconds">
<include resource="org/springframework/boot/logging/logback/base.xml" />
<!-- 日志的级别:debug,info,warn,error -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter> -->
<File>${LOG_PATH}/info.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/pm-info-%d{yyyyMMdd}.log.%i</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>2</maxHistory>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%msg%n
</Pattern>
</layout>
</appender> <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<File>${LOG_PATH}/error.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/pm-error-%d{yyyyMMdd}.log.%i
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>2</maxHistory>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%msg%n </Pattern>
</layout>
</appender>
<root level="INFO">
<appender-ref ref="INFO_FILE" />
<appender-ref ref="ERROR_FILE" />
</root> </configuration>

pm-logback.xml

  部署工程时可以放到工程jar所在文件夹内,部署的工程会自动找到文件;

四、添加Shiro支持功能:

  1、新建shiro配置类,Shiro的主要配置信息都在此文件内实现;

package com.ddd.program.config;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map; import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.session.mgt.SessionManager;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class ShiroConfiguration { /**
* ShiroFilterFactoryBean 处理拦截资源文件问题。
* 注意:单独一个ShiroFilterFactoryBean配置是或报错的
* 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
*/
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager); // 拦截器.
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); //filterChainDefinitionMap.put("/page/*", "authc");
// 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
//filterChainDefinitionMap.put("/security/logoff", "logout"); shiroFilterFactoryBean.setLoginUrl("/#/login");
// 未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/403"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean;
} @Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
MyRealm myRealm = new MyRealm();
securityManager.setRealm(myRealm);
securityManager.setSessionManager(sessionManager());
securityManager.setCacheManager(ehCacheManager());
return securityManager;
} @Bean
public SessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
Collection<SessionListener> listeners = new ArrayList<SessionListener>();
listeners.add(new MySessionListener());
sessionManager.setSessionListeners(listeners);
return sessionManager;
} @Bean
public EhCacheManager ehCacheManager() {
EhCacheManager ehCacheManager = new EhCacheManager();
//ehCacheManager.setCacheManagerConfigFile("classpath:encache.xml");
return ehCacheManager;
} }

  2、新建登录验证和Session监听的类(上面的类所需要的两个类)

    登录相关:

package com.ddd.program.config;

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.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
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.slf4j.Logger;
import org.slf4j.LoggerFactory; import com.cdv.nsite.program.model.AppUser;
import com.cdv.nsite.program.services.impl.AppUserServiceImpl; public class MyRealm extends AuthorizingRealm { private final static Logger logger = LoggerFactory.getLogger(MyRealm.class); @Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
logger.debug("登录验证后进行权限认证....");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
return info;
} @Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
logger.debug("登录操作进行登录认证......");
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken; AppUser user = SpringContextUtils.getBean(AppUserServiceImpl.class).getUserByName(token.getUsername());
if (user == null) {
// 没找到帐号
throw new UnknownAccountException(
"没有在本系统中找到对应的用户信息。");
}
//简单验证
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
user.getUsername(),user.getPassword(),getName()); return info;
} }

MyRealm.java

    Session相关:

package com.ddd.program.config;

import java.util.concurrent.atomic.AtomicInteger;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.SessionListener;
import org.springframework.stereotype.Component; @Component
public class MySessionListener implements SessionListener { private final AtomicInteger sessionCount = new AtomicInteger(0); @Override
public void onStart(Session session) {
sessionCount.incrementAndGet();
System.out.println("登录+1=="+sessionCount.get());
} @Override
public void onStop(Session session) {
sessionCount.decrementAndGet();
System.out.println("登录退出-1=="+sessionCount.get());
} @Override
public void onExpiration(Session session) {
sessionCount.decrementAndGet();
System.out.println("登录过期-1=="+sessionCount.get()); } public int getSessionCount() {
return sessionCount.get();
}
}

MySessionListener.java

  3、添加静态页面:

    在resource文件夹下新建static或public文件夹,工程会默认找static文件夹下的index.*,没有在找public文件夹下的index.*;

  4、新建登录的接口和实现

   完整代码---> https://github.com/liangguang/springboot_18

结述:

  以上代码只是个例子,主要是获得登录的Session用作其他用途;

---------------------------------------------------添加热部署支持-----------------------

  <!-- 模板引擎 暂时不用 -->
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency> -->
<!--
devtools可以实现热部署。devtools会监听classpath下的文件变动,并且会立即重启应用(发生在保存时机),注意:因为其采用的虚拟机机制,该项重启是很快的
如果设置SpringApplication.setRegisterShutdownHook(false),则自动重启将不起作用。
设置 spring.devtools.restart.enabled 属性为false,可以关闭该特性。
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
<!-- optional=true,依赖不会传递,-->
</dependency>

添加devtools依赖

spring.devtools.restart.enabled = true

application.properties中添加配置项;