利用springmvc整合shiro,对不同用户进行权限验证,在现在的开发中很常见,这个简单的案例就是模拟了以下springmvc与shiro的结合
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>
<groupId>com.day512</groupId>
<artifactId>shiro-mvc</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>shiro-mvc Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<!--shiro核心类库-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<!--shiro web-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
<build>
<finalName>shiro-mvc</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>log4j.properties</include>
<include>**/*.ini</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
配置文件
log4j.properties
log4j.rootLogger=WARN, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
2、shiro-web.ini
[users]
root = secret,admin
guest = guest, guest
test = 123456, guest,test
[roles]
#*代表全部权限
admin = *
guest = user:list
#表示拥有menu里面的两个权限
test = menu:list,menu:add
3、spring-config.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:aop="http://www.springframework.org/schema/aop"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--扫描 在该包下处理Controller以外的注解-->
<context:component-scan base-package="com.shiro.mvc">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<!--要读取的文件-->
<bean id="iniRealm" class="org.apache.shiro.realm.text.IniRealm">
<!--要指定的文件的地址-->
<constructor-arg name="resourcePath" value="classpath:shiro-web.ini" />
</bean>
<!--默认的SecurityManager-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!--指定数据源-->
<property name="realm" ref="iniRealm" />
</bean>
<!--开启 @RequiresPermissions注解-->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>
<!--配置Shiro核心过滤器--> <!--注意這個jar包-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!--直接初始化自己的FilterBean-->
<!--<bean id="shiroFilter" class="com.shiro.mvc.filter.MyShiroFilterFactoryBean">-->
<!--将引用的数据源指定到ShiroFilter中来-->
<property name="securityManager" ref="securityManager" />
<!--指定如果没有登录要到的地方-->
<property name="loginUrl" value="/gologin.html" />
<!--登陆成功要跳转的地址-->
<property name="successUrl" value="/index.html" />
<!--验证失败要跳转的地址-->
<property name="unauthorizedUrl" value="/error.html" />
<!--定义过滤规则-->
<property name="filterChainDefinitions">
<value>
/login.html = anon
/gologin.html = anon
/index.html = authc
/role.html = authc,roles[admin]
<!-- springmvc配置-->
/menu/** = authc
</value>
</property>
</bean>
</beans>
webapp/WEB-INF/文件夹下
1、springmvc.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-4.2.xsd">
<!--开启注解-->
<mvc:annotation-driven />
<!--扫描-->
<context:component-scan base-package="com.shiro.mvc.controller">
<!--扫描Controller注解-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<!--配置视图解析器 ,因为在Controller中只返回了视图的名字 这样在Controller中只用返回视图的名字,无需路径就可以了-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--给视图配置一个前缀-->
<property name="prefix" value="/WEB-INF/pages/" />
<!--给视图配置一个后缀-->
<property name="suffix" value=".jsp" />
</bean>
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor">
</bean>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
</bean>
</beans>
2、web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!--指定读取的配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-config.xml</param-value>
</context-param>
<!--监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--配置Shiro核心拦截器-->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
<!--配置Servlet-->
<servlet>
<!--名字必须和xml文件名字一样-->
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
</web-app>
idea中自带的xml文件版本较低,所以可以自己去添加xml配置文件,上面的xml文件都是我自己自定义的。
Controller编写
1、LoginController
package com.shiro.mvc.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
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 javax.servlet.http.HttpServletRequest;
@Controller
public class LoginController {
@RequestMapping("gologin.html")
public String goLogin(){
return "login";
}
@RequestMapping("logout.html")
public String logout(){
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "login";
}
@RequestMapping("login.html")
public String login(String username, String password, HttpServletRequest request){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
try {
//成功跳转到首页
subject.login(token);
return "redirect: /index.html";
} catch (AuthenticationException e) {
e.printStackTrace();
//提示信息
request.setAttribute("error","用户名或密码错误");
//失败依然返回当前的登录页 login.jsp
return "login";
}
}
}
2、MenuController
package com.shiro.mvc.controller;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/menu")
public class MenuController {
@RequestMapping("list.html")
public String list(){
return "/menu_list";
}
@RequestMapping("go_edit.html")
@RequiresPermissions("menu:edit") //开启这个注解需要去修改子容器和父容器
public String goEdit(){
return "/menu_edit";
}
}
3、PageController
package com.shiro.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class PageController {
//返回视图的名字
@RequestMapping("index.html")
public String index(){
return "index";
}
//处理error
@RequestMapping("error.html")
public String error(){
return "error";
}
}
4、exception.AuthExceptionHandler
package com.shiro.mvc.exception;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.servlet.ModelAndView;
@ControllerAdvice
public class AuthExceptionHandler {
//处理这个异常
@ExceptionHandler(UnauthorizedException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public ModelAndView processUnauthenticatedException(NativeWebRequest request, UnauthorizedException e){
//返回error这个页面,返回异常信息
return new ModelAndView("error","exception",e);
}
}