简单记录下学习SpringSecurity的过程:
结构:
1.新建springboot项目,导入依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lys</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.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-web</artifactId>
</dependency>
<!-- 增加数据库支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.7.RELEASE</version>
<configuration>
<mainClass>com.lys.DemoApplication</mainClass>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2.配置文件信息
注意:配置可以登录用户的信息有多种方式:
- 在application.yml中配置
- SecurityConfig 继承WebSecurityConfigurerAdapter,重写configure(AuthenticationManagerBuilder auth) 实现
- 重写UserDetailsService userDetailsService() 方法,通过new JdbcUserDetailsManager()并返回实例用户
spring:
security:
user:
name: lys
password: 123
roles: admin
datasource:
url: jdbc:mysql://localhost:3306/security?serverTimezone=UTC&characterEncoding=UTF-8
username: root
driver-class-name: com.mysql.cj.jdbc.Driver
password: root
3.SecurityConfig配置类
方式一:
package com.lys.config;
import org.springframework.beans.factory.annotation.Autowired;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import javax.sql.DataSource;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
DataSource dataSource;//自动装配数据库源信息
@Override
@Bean
protected UserDetailsService userDetailsService() {
JdbcUserDetailsManager manager = new JdbcUserDetailsManager();
manager.setDataSource(dataSource);
if (!manager.userExists("Tom")) {
manager.createUser(User.withUsername("Tom").password("123").roles("admin").build());
}
if (!manager.userExists("Jack")) {
manager.createUser(User.withUsername("Jack").password("123").roles("user").build());
}
return manager;
}
@Bean
PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance(); //不启用密码加密
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("admin") //只有admin角色可以访问/admin/**下资源
.antMatchers("/user/**").hasRole("user") //只有user角色可以访问/user/**下资源
.anyRequest().authenticated().and()
.formLogin().loginPage("/login.html").defaultSuccessUrl("/index.html") //自定义登录验证页面,登录成功后自动跳转主页
.and()
.logout()
.logoutUrl("/logout") //注销请求
.logoutSuccessUrl("/login.html") //成功注销后重定向回
.deleteCookies() //删除cookies信息
.clearAuthentication(true) //清除身份验证
.invalidateHttpSession(true)
.permitAll()
.and()
.csrf().disable();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring() //设置不拦截的资源
.antMatchers("/js/**", "/css/**", "/images/**");
}
}
方式二:将用户信息写入内存中,这种方式不需要连接数据库
package com.lys.config;
import org.springframework.beans.factory.annotation.Autowired;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import javax.sql.DataSource;
/**
* 简述:
*
* @author:LiYansheng
* @date:2021/08/26 22:43
* @version:
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 身份验证管理器生成器
// 在内存中定义用户信息
auth.inMemoryAuthentication()
.withUser("li")
.password("123")
.roles("user")
.and()
.withUser("lys")
.password(("123"))
.roles("admin");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasRole("user")
.anyRequest().authenticated().and()
.formLogin().loginPage("/login.html").defaultSuccessUrl("/index.html")
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login.html")
.deleteCookies()
.clearAuthentication(true)
.invalidateHttpSession(true)
.permitAll()
.and()
.csrf().disable();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/js/**", "/css/**", "/images/**");
}
}
4.写controller
package com.lys.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello() {
return "hello!!!(任何人都可以访问)";
}
@GetMapping("/user/hello")
public String user() {
return "hello user(专属)";
}
@GetMapping("/admin/hello")
public String admin() {
return "hello,admin(专用)";
}
@RequestMapping("/index")
public String toIndexPage() {
return "/index.html";
}
}
5.自定义前端页面
登录页:login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div style="width: 30%"></div>
<div style="text-align: center;border: 2px solid #2bb3ff;border-radius: 20%;width: 40%">
<form action="/login.html" method="post">
<div class="input">
<label for="name">账号:</label>
<input type="text" name="username" id="name">
<span class="spin"></span>
</div>
<div class="input">
<label for="pass">密码:</label>
<input type="password" name="password" id="pass">
<span class="spin"></span>
</div>
<div class="button login">
<button type="submit">
<span>登录</span>
<i class="fa fa-check"></i>
</button>
</div>
</form>
</div>
<div style="width: 30%"></div>
</body>
</html>
主页:index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>主页</title>
</head>
<body>
<div style="text-align: right">
<a href="/logout">注销</a>
</div>
<div>
<h1>我是首页</h1>
<p>内容balabala</p>
</div>
</body>
</html>
6.登录后跳转的主页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>主页</title>
</head>
<body>
<div style="text-align: right">
<a href="/logout">注销</a>
</div>
<div>
<h1>我是首页</h1>
<p>内容balabala</p>
</div>
</body>
</html>
7.启动器
package com.lys;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author 胜胜
*/
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
8.测试
- 启动项目后访问http://127.0.0.1:8080/hello ,我们会发现并不能直接访问,浏览器会给自动重定向到登录页面
- 我们先用用户“Tom"登录,其角色为”admin",登录成功后,可以看到以下页面,这个页面是所有用户都可以访问的
- 访问首页index.html正常
- 换一个角色是”user"的用户“jack"登录
- 访问/user/hello,可以看到正常显示
- “user"角色访问/admin/hello,可以看到是不能正常访问的,/admin/hello只有”admin"角色的用户可以访问
小白初步尝试,有不对的地方欢迎指正!