1.概述
spring security默认的用户名是user,密码是随机生成的,那么能否自定义用户名和登录密码呢。
spring security 提供给用户一个在整个配置中,扩展自定义逻辑的配置类
主要自定义配置类,并且继承WebSecurityConfigurerAdapter,在类上添加@EnableWebSecurity注解就行,通过它就能实现自定义用户名、密码等信息
此示例,只做入门登录说明,权限的案例详见示例二
访问地址:https://blog.csdn.net/qq_32224047/article/details/108597820
2.实现过程
2.1.1最初版的安全框架
导入依赖
<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-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
自动配置相关的包
2.1.2编写一个启动类
@SpringBootApplication
public class StarterSecurity1 {
public static void main(String[] args) {
SpringApplication.run(StarterSecurity1.class,args);
}
}
因为springboot底层做了security的自动配置,所以启动时就已经有了这个安全框架
在没有任何配置代码情况下,启动后会出现随机的密码,默认的用户名时user
在前端访问,输入默认的用户名和随机的密码登录
登录成功,因为没有写逻辑代码,进入显示异常是正常情况
2.1.3.对上面的代码,添加一个Controller
@RestController
public class AdminController {
@RequestMapping("/admin/write")
public String write() {
return "写入数据";
}
@RequestMapping("/admin/update")
public String update() {
return "更新数据";
}
@RequestMapping("/admin/delete")
public String delete() {
return "删除数据";
}
@RequestMapping("/user/read")
public String read() {
return "读取数据,不需要权限";
}
}
重新运行,选择一个请求地址(如:),在用新生成的随机密码登录
可以看到正常访问
因为没有做限制,所以配置的访问路径登录后都能访问
spring security是通过session 来判断是否是同一个用户登录(jsessionid就是用来判断当前用户对应于哪个session)
更换一个请求地址,可以看到id值没有改变
关闭浏览器,然后session 被删除,需要重新登录,可以看到id的值已经改变
2.2.1自定义一个内存用户
覆盖父类方法configure(AuthenticationManagerBuilder auth)
在这里我们利用内存数据重新定义了2个用户,由于spring security5.x不在使用NoOpPasswordEncoder作为默认密码加密器,否则登录时会抛出异常。
启动器代码
@SpringBootApplication
public class StarterSecurityDemo01 {
public static void main(String[] args) {
SpringApplication.run(StarterSecurityDemo01.class,args);
}
}
SecurityConfig 中的代码,这里使用的是明文加密,实际中不允许使用,这里这做测试用
@Configuration
@EnableWebSecurity
public class MyWebSecurityConfig
extends WebSecurityConfigurerAdapter {
//明文加密器,只需要在内存中有这个管理对象,如果不添加,从前端登录时会抛出异常
@Bean
public PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.userDetailsService(myUserDetailsService());
//auth可以决定user对象的来源,可以是内存,也可以是
//自定义从数据库读取的数据
auth.inMemoryAuthentication()
.withUser("user")
.password("123456")
//.roles("guest")//底层ROLE_guest权限
.authorities("read","ROLE_guest");
//roles 和authorities本质底层都是设置的权限
//在内存用户定义时,同时存在,下面的方法值会覆盖上面的
auth.inMemoryAuthentication()
.withUser("admin")
.password("123456")
.roles("administrator","guest")
.authorities("read","write","delete","update","ROLE_administrator","ROLE_guest");
}
}
测试
启动项目,因为做了配置,所以不会在产生随机的密码
在浏览器输入之前配置的用户名密码验证
可以看到登录访问成功
使用httpbasic认证
SecurityConfig 类中继续覆盖configure方法,完整代码如下
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class MyWebSecurityConfig
extends WebSecurityConfigurerAdapter {
//明文加密器,只需要在内存中有这个管理对象,如果不添加,从前端登录时会抛出异常
@Bean
public PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.userDetailsService(myUserDetailsService());
//auth可以决定user对象的来源,可以是内存,也可以是
//自定义从数据库读取的数据
auth.inMemoryAuthentication()
.withUser("user")
.password("123456")
//.roles("guest")//底层ROLE_guest权限
.authorities("read","ROLE_guest");
//roles 和authorities本质底层都是设置的权限
//在内存用户定义时,同时存在,下面的方法值会覆盖上面的
auth.inMemoryAuthentication()
.withUser("admin")
.password("123456")
.roles("administrator","guest")
.authorities("read","write","delete","update","ROLE_administrator","ROLE_guest");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()// 开启权限控制,自定义逻辑
.anyRequest()//任意请求
.authenticated();//必须进过认证,只要登录就能访问
//http.formLogin();//开启表单认证
http.httpBasic();//开启http 基本认证
}
上面代码中是将http.formLogin();注释掉了的,这样使用的就是httpBasic认证,这是一种简单的,利用客户端(浏览器)和服务器认证方式.认证逻辑用户填写用户名密码
此时访问弹出框的样式
浏览器支持httpbasic 认证 将username:password 文本进行了加密. 添加到请求头中Authorization 值 basic 加密文字,加密算法是base64
登录成功