如何从spring-security3.x升级到4.2.3
从spring-security3.x升级到4.2.3
由于之前spring-security3.x用的是配置文件配置权限校验的,但升级到4.2.3以后,配置文件权限配置都失效了,尤其是UserDetailsService类,完全不走它的loadUserByUsername方法了。
查了很多资料,在官网上也走了很久,发现spring-security4.x的文档比较详细的是java 代码配置。看来spring-security目前推荐使用java配置,xml的完整配置都没有了。
[ spring-security官网例子 ][1]
在官网的例子里试了半天,发现其实官网关于配置文件的例子都不全,虽然感觉是对的,但是配置的项目中,还是非常有问题的,权限并没有生效。
官网一般给的都是这个配置:
<b:beans xmlns="http://www.springframework.org/schema/security"
xmlns:b="http://www.springframework.org/schema/beans"
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">
<http auto-config="true" use-expressions="true">
<intercept-url pattern="auth/login" access="permitAll"/>
<intercept-url pattern="main/admin" access="hasAnyRole('ADMIN')"/>
<intercept-url pattern="/main/common" access="hasRole('USER')"/>
<form-login login-page="/auth/login"
login-processing-url="logIn.do"
authentication-failure-url="/auth/login?error=true"
default-target-url="/main/common"/>
<logout
invalidate-session="true"
logout-success-url="/auth/login"
logout-url="/auth/logout"/>
<access-denied-handler
error-page="/auth/denied"
/>
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="user" password="123456" authorities="USER"/>
</user-service>
</authentication-provider>
</authentication-manager>
</b:beans>
但经测试,通过配置的用户名登陆,只要登陆,它可以访问拥有USER和ADMIN权限的controller。
正常应该user用户只能访问/main/common路径才对。
由于弄了我半天,很头疼,就打算放弃配置文件了。
spring-security4.x 代码配置权限
不管是xml配置还是java配置
web.xml必须要加springSecurityFilterChain:
<!-- SpringSecurity必须的filter -->
<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>
以下是完整的web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>WolfSpringMVC</display-name>
<!-- 默认页面 -->
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
<!-- filter -->
<!-- 字符过滤器 -->
<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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- SpringSecurity必须的filter -->
<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>
<!-- servlet -->
<!-- springMVC的servlet,加载/WEB-INF/conf/spring/springMVC-config.xml文件,启动springMVC
如果没有contextConfigLocation参数,则在/WEB_INF下去找springMVC-servlet.xml文件
-->
<servlet>
<servlet-name>WolfSpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/conf/spring/springMVC-config.xml</param-value>
</init-param>
<!-- 值大于等于0表示容器启动应用时候加载该servlet,数值越小优先级越高 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>WolfSpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- applicationContext.xml -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/conf/spring/applicationContext.xml
<!--/WEB-INF/conf/spring/spring-security.xml-->
</param-value>
</context-param>
<!-- log4j.properties -->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/conf/log/log4j.properties</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
因为是用java去配置spring-security,那么spring-security.xml注释掉,不加载。
以下是我项目的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>springsecurtTest</groupId>
<artifactId>springsecurtTest</artifactId>
<version>4.2.3.RELEASE</version>
<packaging>war</packaging>
<name>spring-security-samples-javaconfig-hellomvc</name>
<description>spring-security-samples-javaconfig-hellomvc</description>
<url>http://spring.io/spring-security</url>
<organization>
<name>spring.io</name>
<url>http://spring.io/</url>
</organization>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>rwinch</id>
<name>Rob Winch</name>
<email>rwinch@gopivotal.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<properties>
<m2eclipse.wtp.contextRoot>/sample</m2eclipse.wtp.contextRoot>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>4.3.9.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>javax.servlet.jsp.jstl-api</artifactId>
<version>1.2.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.4.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.7</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.7</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.7</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.2.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>4.2.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-samples-javaconfig-messages</artifactId>
<version>4.2.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.2.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>opensymphony</groupId>
<artifactId>sitemesh</artifactId>
<version>2.4.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>2.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>4.2.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.6.v20170531</version>
<configuration>
<stopPort>9988</stopPort>
<stopKey>foo</stopKey>
<scanIntervalSeconds>5</scanIntervalSeconds>
<connectors>
<connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
<port>8080</port>
<maxIdleTime>60000</maxIdleTime>
</connector>
</connectors>
<webAppConfig>
<contextPath>/</contextPath>
</webAppConfig>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
关键代码:继承WebSecurityConfigurerAdapter抽象类
WebSecurityConfig类:
@Configuration注解
声明它此类为配置文件,spring-security会加载@EnableWebSecurity 注解
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser(“bill”).password(“abc123”).roles(“USER”);
auth.inMemoryAuthentication().withUser(“admin”).password(“root123”).roles(“ADMIN”);
auth.inMemoryAuthentication().withUser(“dba”).password(“root123”).roles(“ADMIN”,”DBA”);
}@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(“/“,”/auth/**”).permitAll()
.antMatchers(“/main/common”).access(“hasRole(‘USER’)”)
.antMatchers(“/main/admin”).access(“hasRole(‘ADMIN’)”)
.and().formLogin()
.and().exceptionHandling().accessDeniedPage(“/auth/denied”);
}
}
注意,configure重载方法里,formLogin没有加载任何配置,查看源码发现它会默认提供一个loginPage,包括登陆的controller。
由于spring4.x对csrf作了升级,登陆操作必须要传一个csrf的token用来标识登陆授权。所以以前直接写个登陆页面的方式不行了。必须提供csrf的token,才能登陆校验,如果我要自己写登陆页面的话,那必须配置token的生成。页面和配置类都要作很多修改。其它我只要做一个简单登陆演示,我就直接用官网提供的默认登陆页面吧。
配置完成后,执行mvn jetty:run,测试权限ok.
[完整项目代码点击这里下载][2]
[1]: http://docs.spring.io/spring-security/site/docs/4.2.3.RELEASE/reference/htmlsingle/#samples “spring-security官网例子”
[2]: https://github.com/huguiqi/springsecurtTest.git