这里将构建一个简单的web应用,它的网页的路径访问受到Spring Security保护和控制,比如:控制某些路径不能直接访问,需要用户登录后才能访问,某些路径能直接访问。
使用的工具:
- JDK 1.8 及以上
- Maven 3.2 及以上
- IntelliJ IDEA
- html页面使用了thymeleaf模板编写
项目的目录结构:
下面开始一步步构建这个项目:
1.在pom.xml中导入maven的相关依赖
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-security-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-security-test</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
注:可以使用 IntelliJ IDEA 的新建project的 Spring Initializr 选项来勾选相关的依赖避免导入错误,耽误时间
2.编写三个简单页面供用户访问
1.第一个页面home.html
此页面相当于平时所见的网站的主页,即用户不用登录也能访问。代码如下:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<meta charset="UTF-8">
<title>Spring Security Example</title>
</head>
<body>
<h1>Welcome!</h1>
<p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p>
</body>
</html>
页面效果如下:(点击页面中的here会访问下面的hello.html)
2.第二个页面hello.html
此页面表示用户登录后显示的相关页面,代码如下:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<meta charset="UTF-8">
<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>
注:上面代码中使用了 Spring Security 中集成的 HttpServletRequest#getRemoteUser() 来获取登陆的用户名。
页面效果如下:(点击 Sign Out 按钮会退出登录)
3.第三个页面login.html
此页面表示登录页面,代码如下:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<meta charset="UTF-8">
<title>spring security login example</title>
</head>
<body>
<div th:if="${param.error}">
Invalid name or password.
</div>
<div th:if="${param.logout}">
You have been logout 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>
用户名或密码输入错误会显示:Invalid name or password,当退出登录返回此页面时会显示:You have been logout out.
页面效果如下:
3.编写MvcConfig.java控制访问对应路径跳转到指定页面
代码如下:
package com.example.springsecuritytest.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");//表示浏览器访问 "/home" 路径时会跳转到 home.html页面
registry.addViewController("/").setViewName("home");
registry.addViewController("/hello").setViewName("hello");
registry.addViewController("/login").setViewName("login");
}
}
4.编写WebSecurityConfig.java来控制三个页面的访问规则和建立一个默认的账户
代码如下:
package com.example.springsecuritytest.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() //路径"/"和"/home"不需要认证,即不用登录就能访问
.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(); //一个账号,用户名为:user,密码为:password
return new InMemoryUserDetailsManager(user);
}
}
5.启动类
代码如下:
package com.example.springsecuritytest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringSecurityTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringSecurityTestApplication.class, args);
}
}
好了,现在就可以启动项目了,完成了用户认证功能,和访问权限的控制