最近SpringBoot2.0推出了,一直没去看,今天按照官网的guide跑了一个security的demo,确实感受到一些变化,基本都是语法方面的改动。
SpringBoot整合SpringSecurity的demo最详细的最全面的还是官网:https://spring.io/guides/gs/securing-web/
所需要的环境:jdk1.8+,springboot2.0
平台:ubuntu,meclipse
项目结构如下:
首先是pom.xml文件:
<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.0modelVersion>
<groupId>SpringSecurityDemogroupId>
<artifactId>SpringSecurityDemoartifactId>
<version>0.0.1-SNAPSHOTversion>
<packaging>warpackaging>
<name>SpringSecurityDemoname>
<description/>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.0.0.RELEASEversion>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.securitygroupId>
<artifactId>spring-security-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-securityartifactId>
dependency>
dependencies>
<properties>
<java.version>1.8java.version>
properties>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-pluginartifactId>
<version>2.3.2version>
<configuration>
<source>1.8source>
<target>1.8target>
configuration>
plugin>
<plugin>
<artifactId>maven-war-pluginartifactId>
<version>2.6version>
<configuration>
<failOnMissingWebXml>falsefailOnMissingWebXml>
configuration>
plugin>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
<repositories>
<repository>
<id>spring-releasesid>
<name>Spring Releasesname>
<url>https://repo.spring.io/libs-releaseurl>
repository>
repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releasesid>
<name>Spring Releasesname>
<url>https://repo.spring.io/libs-releaseurl>
pluginRepository>
pluginRepositories>
project>
然后是几个简单页面:
hello.html:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Hello World!title>
head>
<body>
<h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!h1>
<form th:action="@{/logout}" method="post">
<input type="submit" value="Sign Out"/>
form>
body>
html>
home.html:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Exampletitle>
head>
<body>
<h1>Welcome!h1>
<p>Click <a th:href="@{/hello}">herea> to see a greeting.p>
body>
html>
login.html:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example title>
head>
<body>
<div th:if="${param.error}">
Invalid username and password.
div>
<div th:if="${param.logout}">
You have been logged out.
div>
<form th:action="@{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> label>div>
<div><label> Password: <input type="password" name="password"/> label>div>
<div><input type="submit" value="Sign In"/>div>
form>
body>
html>
光看前端页面觉得平平无奇,可是后台逻辑的处理就与2.0以前的版本有区别了:
路由控制类:MvcConfig.java
package hello;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
registry.addViewController("/").setViewName("home");
registry.addViewController("/hello").setViewName("hello");
registry.addViewController("/login").setViewName("login");
}
}
以前的路由控制是直接在方法上面加注解指定路由,现在是统一在一个类中,有点类似于struts了,不过这也方便管理,addViewControllers()方法(在WebMvcConfigurer中覆盖相同名称的方法)添加了四个视图控制器。两个视图控制器引用名称为“home”的视图(在home.html中定义),另一个引用名为“hello”的视图(在hello.html中定义)。第四个视图控制器引用另一个名为“login”的视图。这样的设置是没有验证的,直接跳转,而无需登录。
security配置类:WebSecurityConfig.java
package hello;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Bean
@Override
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
如果要防止未经授权的用户在“/hello”中查看hello页面。需要添加一个拦截,强制用户在看到该页面之前登录。
WebSecurityConfig类使用@EnableWebSecurity进行注释,以支持Spring Security的web安全支持,并提供Spring MVC集成。它还扩展了WebSecurityConfigurerAdapter通过覆盖方法来自定义设置一些配置。
configure(HttpSecurity)方法定义了哪些URL路径应该被保护,哪些不应该被保护。其中“/”和“/home”路径被配置为不需要任何身份验证。其他所有其他路径都必须经过身份验证。
当用户成功登录时,被重定向到先前请求的页面,该页面需要身份验证。有一个由loginPage()指定的自定义“/登录”页面,这个也是无需身份验证的。
userDetailsService()方法,设置一个存储在内存中的用户,并使用单个用户。该用户被赋予“user”的用户名,“password”的密码,以及“USER”的角色。
总结为一句话:Spring Security提供了一个过滤器,可以拦截该请求并对用户进行身份验证。
程序启动入口类:Application.java
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) throws Throwable {
SpringApplication.run(Application.class, args);
}
}
测试: