1. 今日内容
文章目录
2. ssm整合spring-security
ssm整合spring-security后,整个请求处理的流程图:
* 流程详解:
1. 前端发送的所以请求都应该被`spring-security`拦截
2. `spring-security`拦截后判断该请求是否是登入请求,即否是`login-processing-url`指定的请求
* 若不是,则一律响应给用户login-page指定的页面
* 若是,则spring-security内部判断该用户是否有权限
* 若没有,则响应给用户authentication-failure-url指定的页面
* 若有,则进行第3步
3. 跳转到default-target-url指定的页面,跳转成功后发出authentication-success-forward-url指定的请求给springmvc处理
同时给用户一个cookie,下次用户再访问资源时,spring-security根据cookie验证,没有cookie再跳转到login-page指定的登入页面
整合步骤:
配置ssm的web.xml文件,在该文件中加载spring-security.xml文件:
<!-- 配置加载类路径的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml,classpath*:spring-security.xml</param-value>
</context-param>
再设置过滤器,哪些请求给spring-security先处理:
<!-- 拦截哪些请求给spring-security处理验证 -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
这样就整合好了,很简单,但是你可能遇到一些问题,后面介绍。
我的ssm的web.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app.xsd"
version="3.1">
<!-- 配置加载类路径的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml,classpath*:spring-security.xml</param-value>
</context-param>
<!-- 配置监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 解决中文乱码过滤器 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 拦截哪些请求给spring-security处理验证 -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 前端控制器(加载classpath:springmvc.xml 服务器启动创建servlet) -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置初始化参数,创建完DispatcherServlet对象,加载springmvc.xml配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!-- 服务器启动的时候,让DispatcherServlet对象创建 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
3. 整合过程中遇到的问题
3.1 404错误
3.1.1 第一种可能
如果你设置的登入页面是.html
页面,则会出现404
的问题。因为spring-security要操作页面,都是请求springmvc得到的。spring-security要跳转到login-page="/ogin.html"
,会给springmvc发送/login
的请求,而html是静态资源,如果你不在spring-mvc.xml配置
文件中设置允许该静态资源允许被访问,则会找不到资源。
所以,在spring-mvc.xml配置
文件中编写一下代码:
<mvc:resources location="/login.html" mapping="/login.html"/>
然后就可以访问资源了。不过个人建议用jsp比较好。
3.1.2 第二种可能
没有在spring-security.xml中设置csrf:<security:csrf disabled="true"/>
,其位置如下:
<security:http auto-config="true" use-expressions="false">
<!-- 配置资料连接,表示任意路径都需要ROLE_USER权限 -->
<security:intercept-url pattern="/**" access="ROLE_USER"/>
<security:form-login
login-page="/pages/login.jsp"
login-processing-url="/login"
username-parameter="username"
password-parameter="password"
authentication-failure-url="/pages/failure.jsp"
default-target-url="/pages/success.jsp"
always-use-default-target="true"
/>
<security:logout invalidate-session="true" logout-url="/logout"
logout-success-url="/login.jsp"/>
<!-- 关闭CSRF,默认是开启的 -->
<security:csrf disabled="true"/>
</security:http>
3.2 页面上显示错误“重定向请求过多”
你用spring-security拦截了所有的请求,但是,请求登入界面的请求不应该被拦截,不然就陷入了死循环,一直重定向,造成此错误。
应该设置:<security:http security="none" pattern="/pages/login.jsp"/>
,表示不过滤某些请求,其位置如下:
<!-- 配置不过滤的资源(静态资源及登录相关) -->
<security:http security="none" pattern="/pages/login.jsp"/>
<security:http auto-config="true" use-expressions="false">
<!-- 配置资料连接,表示任意路径都需要ROLE_USER权限 -->
<security:intercept-url pattern="/**" access="ROLE_USER"/>
<security:form-login
login-page="/pages/login.jsp"
login-processing-url="/login"
username-parameter="username"
password-parameter="password"
authentication-failure-url="/pages/failure.jsp"
default-target-url="/pages/success.jsp"
always-use-default-target="true"
/>
<security:logout invalidate-session="true" logout-url="/logout"
logout-success-url="/login.jsp"/>
<!-- 关闭CSRF,默认是开启的 -->
<security:csrf disabled="true"/>
</security:http>
3.3 无论登入成功还是失败一直重定向在登入界面
3.3.1 第一个可能
出现这个原因,你应该和我一样用的是jsp文件,我都网上翻了各种资料,找了好几个小时,没找到。第二天自己无意间把错误找到了:
在登入的login.jsp
页面中,登入的请求必须要绝对请求路径,不能用相对请求路径:
必须这样:
<form action="${pageContext.request.contextPath}/login" method="post">
不能这样:
<form action="login" method="post">
3.3.2 第二个可能
登陆界面的请求与login-processing-url请求的名字不一样:
<form action="${pageContext.request.contextPath}/login" method="post">
login-processing-url="/login"
这里 action="${pageContext.request.contextPath}/XXX" 和 login-processing-url="/XXX"
这里的XXX必须一致
这样基本上没有问题了。
4. 最后附上我的ssm整合spring-security项目
项目结构:
效果:
4.1 web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app.xsd"
version="3.1">
<!-- 配置加载类路径的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml,classpath*:spring-security.xml</param-value>
</context-param>
<!-- 配置监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 解决中文乱码过滤器 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 拦截哪些请求给spring-security处理验证 -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 前端控制器(加载classpath:springmvc.xml 服务器启动创建servlet) -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置初始化参数,创建完DispatcherServlet对象,加载springmvc.xml配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!-- 服务器启动的时候,让DispatcherServlet对象创建 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
4.2 spring-security.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<!-- 配置不过滤的资源(静态资源及登录相关) -->
<security:http security="none" pattern="/login.do"/>
<security:http security="none" pattern="/login.do?error=a"/>
<security:http auto-config="true" use-expressions="false">
<!-- 配置资料连接,表示任意路径都需要ROLE_USER权限 -->
<security:intercept-url pattern="/**" access="ROLE_USER"/>
<!-- 自定义登陆页面
login-page 登陆页面
login-processing-url : 发送登陆请求数据的url
authentication-failure-url 用户权限校验失败后后才会跳转到这个页面,
default-target-url 登陆成功后跳转的页面。
always-use-default-target: true 适用于后台管理系统,防止访问历史记录
false 适用于前台页面,提升用户体验
-->
<security:form-login
login-page="/login.do"
login-processing-url="/login"
username-parameter="username"
password-parameter="password"
authentication-failure-url="/login.do?error=a"
default-target-url="/pages/success.jsp"
always-use-default-target="true"
/>
<!-- 登出:
invalidate-session 是否删除session
logout-url:登出处理链接
logout-successurl:登出成功页面
注:登出操作 只需要链接到 logout即可登出当前用户
-->
<security:logout
invalidate-session="true"
logout-url="/logout"
logout-success-url="/login.do?logout"/>
<!-- 关闭CSRF,默认是开启的 -->
<security:csrf disabled="true"/>
</security:http>
<!-- 在内存中构造用户们 -->
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="user" password="{noop}user" authorities="ROLE_USER"/>
<security:user name="admin" password="{noop}admin" authorities="ROLE_ADMIN"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
</beans>
4.3 spring-mvc.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 扫描controller的注解,别的不扫描 -->
<context:component-scan base-package="cn.wanghao.springSecurity.controller"></context:component-scan>
<!-- 开启对SpringMVC注解的支持 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 配置视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- JSP文件所在的目录 -->
<property name="prefix" value="/pages/"></property>
<!-- 文件的后缀名 -->
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 设置静态资源不过滤 -->
<!--<mvc:resources location="/css/" mapping="/css/**"/>-->
<!--<mvc:resources location="/images/" mapping="/images/**"/>-->
<!--<mvc:resources location="/js/" mapping="/js/**"/>-->
</beans>
4.4 login.jsp文件
<%--
Created by IntelliJ IDEA.
User: WangHao
Date: 2020/4/4
Time: 16:24
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/login" method="post">
<label>用户名:</label> <input type="text" name="username"> <br>
<label>密码:</label> <input type="password" name="password"> <br>
<input type="submit" value="提交"> <input type="reset" value="重置"/>
<span>
<c:if test="${not empty error}">
<div>${error}</div>
</c:if>
<c:if test="${not empty logout}">
<div>${logout}</div>
</c:if>
</span>
</form>
</body>
</html>
4.5 success.jsp
<%--
Created by IntelliJ IDEA.
User: WangHao
Date: 2020/4/4
Time: 14:18
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
恭喜您,自定义登入设置成功!<br>
<a href="${pageContext.request.contextPath}/logout">注销</a>
</body>
</html>
4.6 LoginController.java
package cn.wanghao.springSecurity.controller;
import cn.wanghao.springSecurity.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class LoginController {
/**
* 处理登入请求
* 1. 不带error、logout参数时,跳转到登入页面
* 2. 带error时,表示登入失败,需要返回给前端登陆失败的信息
* 3. 带logout时,表示注销,需要返回给前端注销成功的信息
* @param error
* @param logout
* @return 跳转登陆页面
*/
@RequestMapping("/login.do")
public ModelAndView login(
@RequestParam(value = "error", required = false)String error,
@RequestParam(value = "logout", required = false)String logout) {
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "登入失败!");
}
if (logout != null) {
model.addObject("logout", "注销成功!");
}
model.setViewName("login");
return model;
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/84640.html