Java 开发领域常见的安全框架有 Shiro 和 Spring Security ,本文主要讲解Spring Security
一、首先创建springboot项目
创建springboot项目参考https://blog.csdn.net/weixin_40009737/article/details/105773950
二、spring security 简介
Spring Security 是一个相对复杂的安全管理框架,功能比 Shiro 更加强大,权限控制细粒度更高,对 OAuth 2 的支持也更友好。
由于 Spring Security 源自 Spring 家族,因此可以和 Spring 框架无缝整合,特别是 Spring Boot 中提供的自动化配置方案,可以让 Spring Security 的使用更加便捷。
spring security 的核心功能主要包括:
认证 (你是谁)
授权 (你能干什么)
攻击防护 (防止伪造身份)
其核心就是一组过滤器链,项目启动后将会自动配置。最核心的就是 Basic Authentication Filter 用来认证用户的身份,一个在spring security中一种过滤器处理一种认证方式。
1.查看pom.xml文件已引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2.创建一个TestController.java
(1)首先在项目添加一个简单的 /hello 接口:
package com.example.securitydemo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@GetMapping("/hello")
public String hello() {
return "欢迎访问 security-demo !";
}
}
(2)接着启动项目,直接访问 /hello 接口则会自动跳转到登录页面(这个登录页面是由 Spring Security 提供的)
(3)我们必须登录后才能访问 /hello 接口。默认用户名是 user,而登录密码则在每次启动项目时随机生成,我们可以在项目启动日志中找到。
登录之后进入/hello 接口
3.用户名和密码配置
这个随机生成的密码,每次启动时都会变。对登录的用户名/密码进行配置,有三种不同的方式:
1.在 application.properties 中进行配置
2.通过 Java 代码配置在内存中
3.通过 Java 从数据库中加载
前两种比较简单,第三种代码量略大,本文就先来看看前两种,第三种后面再单独写文章介绍。]
3.1在配置文件 中进行配置用户名/密码
可以直接在 application.properties 文件中配置用户的基本信息:
如果对默认的用户名和密码不满意,可以在 application.properties 中配置默认的用户名、密码和角色。这样项目启动后就不会随机生成密码了,而是使用我们配置的用户、密码,并且登录后还具有一个 admin 角色(关于角色的用法再后面的文章会相信介绍)。
spring.security.user.name=user
spring.security.user.password=1234
spring.security.user.roles=admin
配置完成后,重启项目,就可以使用这里配置的用户名/密码登录了。
3.2Java 配置用户名/密码
(1)我们可以通过自定义类继承 WebSecurityConfigurerAdapter,从而实现对 Spring Security 更多的自定义配置。比如下面样例我们就配置了两个用户,以及他们对应的角色。
基于内存的用户配置在配置角色时不需要添加“ROLE_”前缀
package com.example.securitydemo.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
// 指定密码的加密方式
@SuppressWarnings("deprecation")
@Bean
PasswordEncoder passwordEncoder(){
// 不对密码进行加密
return NoOpPasswordEncoder.getInstance();
}
// 配置用户及其对应的角色
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin1").password("1234").roles("ADMIN","USER")
.and()
.withUser("user1").password("1234").roles("USER");
}
}
(2)配置完成后,重启项目,就可以使用这两个用户进行登录了。
(3)配置 URL 访问权限
1.上面配置完毕后受保护的资源都是默认的(不同角色访问权限也没有什么不同),而真正项目中我们需要根据实际情况进行角色管理。要实现这个功能只需重写 WebSecurityConfigurerAdapter 中的另一个方法即可:
formLogin() 方法表示开启表单登录,即我们之前看到的登录页面。
loginProcessingUrl() 方法配置登录接口为“/login”,即可以直接调用“/login”接口,发起一个 POST 请求进行登录,登录参数中用户名必须为 username,密码必须为 password,配置 loginProcessingUrl 接口主要是方便 Ajax 或者移动端调用登录接口。
permitAll() 表示和登录相关的接口都不需要认证即可访问
package com.example.securitydemo.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
// 指定密码的加密方式
@SuppressWarnings("deprecation")
@Bean
PasswordEncoder passwordEncoder(){
// 不对密码进行加密
return NoOpPasswordEncoder.getInstance();
}
// 配置用户及其对应的角色
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("root").password("1234").roles("ADMIN","ROOT")
.and()
.withUser("admin1").password("1234").roles("ADMIN","USER")
.and()
.withUser("user1").password("1234").roles("USER");
}
// 配置 URL 访问权限
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() // 开启 HttpSecurity 配置
.antMatchers("/admin/**").hasRole("ADMIN") // admin/** 模式URL必须具备ADMIN角色
.antMatchers("/user/**").access("hasAnyRole('ADMIN','USER')") // 该模式需要ADMIN或USER角色
.antMatchers("/root/**").access("hasRole('ADMIN') and hasRole('ROOT')") // 需ADMIN和DBA角色
.anyRequest().authenticated() // 用户访问其它URL都必须认证后访问(登录后访问)
.and().formLogin().loginProcessingUrl("/login").permitAll() // 开启表单登录并配置登录接口
.and().csrf().disable(); // 关闭csrf
}
}
2.接着在 Conctoller 中添加如下接口进行测试:
package com.example.securitydemo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@GetMapping("/hello")
public String hello() {
return "欢迎访问 security-demo !";
}
@GetMapping("/admin/hello")
public String admin() {
return "hello admin";
}
@GetMapping("/user/hello")
public String user() {
return "hello user";
}
@GetMapping("/root/hello")
public String db() {
return "hello root";
}
}
3.接下来测试一下,我们使用 admin1 用户进行登录,由于该用户具有 ADMIN 和 USER 这两个角色,所以登录后可以访问 /hello、/admin/hello 以及 /user/hello 这三个接口。
4而由于 /root/hello 接口同时需要 ADMIN 和 DBA 角色,因此 admin1 用户仍然无法访问。