读者福利
分享一份自己整理好的Java面试手册,还有一些面试题pdf
不要停下自己学习的脚步
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
控制器 IndexController.java
package com.example.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
@GetMapping("/")
public String index(){
return "Hello";
}
}
直接访问应用会被重定向到登录页面
http://localhost:8080/
=> 302
http://localhost:8080/login
现在使用默认的账号密码登录
- 默认的用户名:user
- 默认的密码:(控制台打印出的密码)
Using generated security password: cdd28beb-9a64-4130-be58-6bde1684476d
可以看到返回结果
二、认证与授权
- 认证 authentication 用户身份
- 授权 authorization 用户权限
单体应用
微服务架构
三、Spring Security基础认证与表单认证
认证方式 | 有无状态 | 简介 | 应用场景 |
---|---|---|---|
基础认证 | 无状态 | 不使用cookie | 对外API |
表单认证 | 有状态 | 使用session会话 | 网站应用 |
- 用户对象 UserDetails
- 内存存储
- 数据库存储
- 认证对象 Authentication
- HTTP基础认证
- HTTP表单认证
1、HTTP基础认证
通过HTTP请求头携带用户名和密码进行登录认证
HTTP请求头格式
# 用户名和密码的Base64编码
Authonrization: Basic Base64-encoded(username:password)
Spring Boot2.4版本以前
package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// 所有请求都需要认证,认证方式:httpBasic
http.authorizeHttpRequests((auth) -> {
auth.anyRequest().authenticated();
}).httpBasic(Customizer.withDefaults());
}
}
Spring Boot2.4版本之后
package com.example.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// 所有请求都需要认证,认证方式:httpBasic
http.authorizeHttpRequests((auth) -> {
auth.anyRequest().authenticated();
}).httpBasic(Customizer.withDefaults());
return http.build();
}
}
发送HTTP请求
GET http://localhost:8080/
Authorization: Basic dXNlcjo2ZjRhMGY5ZS1hY2ZkLTRmNTYtYjIzNy01MTZmYmZjMTk3NGM=
可以获得响应数据
Hello
base64解码之后可以得到用户名和密码
atob('dXNlcjo2ZjRhMGY5ZS1hY2ZkLTRmNTYtYjIzNy01MTZmYmZjMTk3NGM=')
'user:6f4a0f9e-acfd-4f56-b237-516fbfc1974c'
2、HTTP表单认证
Spring Security的默认认证方式
四、Spring Security 用户与认证对象
1、用户对象
接口名 | 说明 |
---|---|
UserDetails | 用户对象 |
GrantedAuthority | 用户权限 |
UserDetailsService | 用户对象查询操作 |
UserDetailsManager | 创建用户、修改用户密码 |
UserDetails 用户对象接口
package org.springframework.security.core.userdetails;
import java.io.Serializable;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
public interface UserDetails extends Serializable {
// 获取用户权限信息
Collection<? extends GrantedAuthority> getAuthorities();
// 获取密码
java.lang.String getPassword();
// 获取用户名
java.lang.String getUsername();
// 判断账户是否失效
boolean isAccountNonExpired();
// 判断账户是否锁定
boolean isAccountNonLocked();
// 判断账户凭证信息是否已失效
boolean isCredentialsNonExpired();
// 判断账户是否可用
boolean isEnabled();
}
GrantedAuthority 用户拥有权限接口
package org.springframework.security.core;
import java.io.Serializable;
public interface GrantedAuthority extends Serializable {
// 获取权限信息
String getAuthority();
}
UserDetailsService 用户查询操作
package org.springframework.security.core.userdetails;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
public interface UserDetailsService {
// 根据用户名获取用户信息
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
UserDetailsManager 用户CRUD操作
package org.springframework.security.provisioning;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
public interface UserDetailsManager extends UserDetailsService {
// 创建用户
void createUser(UserDetails user);
// 更新用户
void updateUser(UserDetails user);
// 删除用户
void deleteUser(String username);
// 修改密码
void changePassword(String oldPassword, String newPassword);
// 判断用户是否存在
boolean userExists(String username);
}
2、认证对象
接口名 | 说明 |
---|---|
Authentication | 认证请求详细信息 |
AuthenticationProvider | 认证的业务执行者 |
Authentication 认证请求详细信息
package org.springframework.security.core;
import java.io.Serializable;
import java.security.Principal;
import java.util.Collection;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.context.SecurityContextHolder;
public interface Authentication extends Principal, Serializable {
// 安全主体所具有的的权限
Collection<? extends GrantedAuthority> getAuthorities();
// 证明主体有效性的凭证
Object getCredentials();
// 认证请求的明细信息
Object getDetails();
// 主体的标识信息
Object getPrincipal();
// 是否认证通过
boolean isAuthenticated();
// 设置认证结果
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}
AuthenticationProvider 认证的业务执行者
package org.springframework.security.authentication;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
public interface AuthenticationProvider {
// 执行认证,返回认证结果
Authentication authenticate(Authentication authentication) throws AuthenticationException;
// 判断是否支持当前的认证对象
boolean supports(Class<?> authentication);
}
五、基于MySQL自定义认证过程
1、项目结构
$ tree -I target
.
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ └── demo
│ │ ├── Application.java
│ │ ├── controller
│ │ │ └── IndexController.java
│ │ ├── entity
│ │ │ └── User.java
│ │ ├── mapper
│ │ │ └── UserMapper.java
│ │ ├── security
│ │ │ ├── SecurityConfiguration.java
│ │ │ └── UserAuthenticationProvider.java
│ │ └── service
│ │ ├── UserService.java
│ │ └── impl
│ │ └── UserServiceImpl.java
│ └── resources
│ ├── application.yml
│ ├── sql
│ │ └── schema.sql
│ ├── static
│ └── templates
└── test
├── http
│ └── IndexController.http
└── java
└── com
└── example
└── demo
└── ApplicationTests.java
2、用户表
默认表结构的SQL路径
spring-security-core-5.7.6.jar!/org/springframework/security/core/userdetails/jdbc/users.ddl
create table users(
username varchar_ignorecase(50) not null primary key,
password varchar_ignorecase(500) not null,
enabled boolean not null
);
create table authorities (
username varchar_ignorecase(50) not null,
authority varchar_ignorecase(50) not null,
constraint fk_authorities_users foreign key(username) references users(username)
);
create unique index ix_auth_username on authorities (username,authority);
一般情况下,我们使用自己创建的用户表
schema.sql
-- 创建用户表
CREATE TABLE `tb\_user` (
`id` int NOT NULL AUTO\_INCREMENT COMMENT '主键id',
`username` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名',
`password` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '密码',
`nickname` varchar(32) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '昵称',
`enabled` tinyint NOT NULL DEFAULT '1' COMMENT '账号可用标识',
PRIMARY KEY (`id`),
UNIQUE KEY `idx\_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户表';
-- 添加初始数据
insert into `tb\_user` values (1, "zhangsan", "zhangsan", "张三", 1);
insert into `tb\_user` values (2, "lisi", "lisi", "李四", 1);
insert into `tb\_user` values (3, "wangwu", "wangwu", "王五", 1);
3、依赖
- Spring Security
- MyBatis-Plus
- MySQL8 JDBC
- Lombok
完整依赖
pom.xml
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</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>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
4、数据库配置
application.yml
server:
port: 8080
# DataSource Config
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/data?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
mybatis-plus:
configuration:
# 开启SQL语句打印
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
# 自增主键策略
id-type: AUTO
5、SpringBoot基本框架
启动类 Application.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
实体类 User.java
package com.example.demo.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Arrays;
import java.util.Collection;
@Data
@TableName("tb\_user")
public class User implements UserDetails {
/\*\*
\* 主键id
\*/
@TableId
private Long id;
/\*\*
\* 用户名
\*/
private String username;
/\*\*
\* 密码
\*/
private String password;
/\*\*
\* 昵称
\*/
private String nickname;
/\*\*
\* 账号可用标识
\*/
private Integer enabled;
/\*\*
\* 获取用户权限信息
\*
\* @return
\*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE\_USER"));
}
/\*\*
\* 判断账户是否失效
\*
\* @return
\*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/\*\*
\* 判断账户是否锁定
\*
\* @return
\*/
@Override
public boolean isAccountNonLocked() {
return true;
}
/\*\*
\* 判断账户凭证信息是否已失效
\*
\* @return
\*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/\*\*
\* 判断账户是否可用
\*
\* @return
\*/
@Override
public boolean isEnabled() {
return this.enabled == 1;
}
}
UserMapper.java
package com.example.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
UserService.java
package com.example.demo.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.demo.entity.User;
public interface UserService extends IService<User> {
}
UserServiceImpl.java
package com.example.demo.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class UserServiceImpl
extends ServiceImpl<UserMapper, User>
implements UserService, UserDetailsService {
/\*\*
\* 根据用户名获取用户信息
\* @param username
\* @return UserDetails
\* @throws UsernameNotFoundException
\*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getUsername, username);
User user = super.getOne(queryWrapper);
if(user == null){
log.error("Access Denied, user not found:" + username);
throw new UsernameNotFoundException("user not found:" + username);
}
return user;
}
}
IndexController.java
package com.example.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
@GetMapping("/hello")
public String hello(){
return "Hello";
}
}
6、自动定义Spring Security
SecurityConfiguration.java
package com.example.demo.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfiguration {
/\*\*
\* 基于基础认证模式
\* @param http
\* @return
\* @throws Exception
\*/
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// 所有请求都需要认证,认证方式:httpBasic
http.authorizeHttpRequests((auth) -> {
auth.anyRequest().authenticated();
}).httpBasic(Customizer.withDefaults());
return http.build();
}
}
## 最后
**码字不易,觉得有帮助的可以帮忙点个赞,让更多有需要的人看到**
又是一年求职季,在这里,我为各位准备了一套Java程序员精选高频面试笔试真题,来帮助大家攻下BAT的offer,题目范围从初级的Java基础到高级的分布式架构等等一系列的面试题和答案,用于给大家作为参考
以下是部分内容截图
![架构面试专题及架构学习笔记导图.png](https://img-blog.csdnimg.cn/img_convert/6aa65e870cda0d167160bf1ff6fffbd6.webp?x-oss-process=image/format,png)
> **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)收录**
**[需要这份系统化的资料的朋友,可以点击这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**
gframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfiguration {
/\*\*
\* 基于基础认证模式
\* @param http
\* @return
\* @throws Exception
\*/
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// 所有请求都需要认证,认证方式:httpBasic
http.authorizeHttpRequests((auth) -> {
auth.anyRequest().authenticated();
}).httpBasic(Customizer.withDefaults());
return http.build();
}
}
## 最后
**码字不易,觉得有帮助的可以帮忙点个赞,让更多有需要的人看到**
又是一年求职季,在这里,我为各位准备了一套Java程序员精选高频面试笔试真题,来帮助大家攻下BAT的offer,题目范围从初级的Java基础到高级的分布式架构等等一系列的面试题和答案,用于给大家作为参考
以下是部分内容截图
[外链图片转存中...(img-q86je9ex-1715455571010)]
> **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)收录**
**[需要这份系统化的资料的朋友,可以点击这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**