spring boot security oauth2 实现支持jwt令牌的授权服务器
时间: 2023-11-16 19:02:22 浏览: 65
Spring Boot Security OAuth2是基于Spring Security和OAuth2的框架,用于实现授权服务器和资源服务器。JWT令牌是一个基于JSON的开放标准,用于在各方之间安全地传输信息。
在Spring Boot Security OAuth2中实现支持JWT令牌的授权服务器,可以按照以下步骤进行:
1. 添加依赖:在项目的pom.xml文件中添加Spring Security OAuth2和JWT的相关依赖。
2. 配置授权服务器:在Spring Boot应用程序的配置文件中,配置授权服务器的基本设置,包括端点URL、客户端信息、用户认证信息等。
3. 配置JWT令牌:配置JWT令牌的签名密钥和过期时间等信息。可以使用开源库如jjwt来生成和验证JWT令牌。
4. 创建自定义的认证提供程序:实现自定义的认证提供程序来支持JWT令牌的认证机制。在认证提供程序中,可以使用JWT令牌解析并验证请求中的令牌信息。
5. 创建自定义的用户详细信息服务:实现自定义的用户详细信息服务,用于从数据库或其他存储中获取用户的详细信息。在用户详细信息服务中,可以根据JWT令牌中的信息获取用户信息。
6. 配置授权服务器的访问规则:配置授权服务器的访问规则,包括允许或禁止特定角色或权限的访问。
7. 测试访问授权服务器:使用客户端应用程序发送请求到授权服务器的端点,获取JWT令牌并验证其有效性。
通过以上步骤,可以实现一个支持JWT令牌的授权服务器。该服务器可以提供为客户端应用程序颁发和验证JWT令牌的功能,以实现安全并可靠的用户认证和授权控制。
相关问题
Spring Boot Security OAuth2 JWT代码
以下是一个基于Spring Boot Security、OAuth2和JWT实现的示例代码:
1. 添加Maven依赖
在pom.xml文件中添加以下依赖:
```
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
```
2. 配置Spring Security
在Spring Boot应用程序中,您可以通过@Configuration配置类来配置Spring Security。以下是一个示例配置类:
```
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/oauth/**").permitAll()
.antMatchers("/api/**").authenticated()
.and()
.formLogin().permitAll()
.and()
.logout().permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
}
```
在上面的配置类中,我们禁用了CSRF保护,并配置了访问权限。具体来说:
- /oauth/** URL模式应该允许所有人访问,因为我们将使用OAuth2协议进行身份验证和授权。
- /api/** URL模式应该需要身份验证。
- 我们还配置了表单登录和注销。
3. 配置OAuth2
在Spring Boot应用程序中,您可以使用@Configuration配置类来配置OAuth2。以下是一个示例配置类:
```
@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("my-signing-key"); // 设置JWT签名密钥
return converter;
}
@Bean
public JwtTokenStore jwtTokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("my-client-id")
.secret(passwordEncoder.encode("my-client-secret"))
.authorizedGrantTypes("password", "refresh_token")
.scopes("read", "write")
.accessTokenValiditySeconds(3600)
.refreshTokenValiditySeconds(86400);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService)
.accessTokenConverter(jwtAccessTokenConverter())
.tokenStore(jwtTokenStore());
}
}
```
在上面的配置类中,我们使用@EnableAuthorizationServer注释启用OAuth2,并实现了AuthorizationServerConfigurer接口以配置客户端和端点。具体来说:
- 我们配置了一个内存中的客户端,使用密码和刷新令牌授权类型,以及读写作用域。
- 我们还配置了JWT令牌转换器和令牌存储。
- 我们将身份验证管理器、用户详细信息服务、JWT令牌转换器和令牌存储配置为端点。
4. 实现用户详细信息服务
我们需要实现UserDetailsService接口来加载用户详细信息。以下是一个示例实现:
```
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found with username: " + username);
}
return new org.springframework.security.core.userdetails.User(
user.getUsername(), user.getPassword(), Collections.emptyList());
}
}
```
在上面的实现中,我们使用Spring Data JPA从数据库中加载用户,并创建一个SimpleGrantedAuthority对象列表作为用户的权限。
5. 实现密码编码器
我们需要实现PasswordEncoder接口,以便在创建用户时对密码进行编码。以下是一个示例实现:
```
@Service
public class PasswordEncoderImpl implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {
return BCrypt.hashpw(rawPassword.toString(), BCrypt.gensalt());
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return BCrypt.checkpw(rawPassword.toString(), encodedPassword);
}
}
```
在上面的实现中,我们使用BCrypt编码算法对密码进行编码和验证。
6. 实现控制器
最后,我们需要实现一个控制器来测试OAuth2和JWT。以下是一个示例实现:
```
@RestController
@RequestMapping("/api")
public class ApiController {
@GetMapping("/hello")
public String hello() {
return "Hello, World!";
}
@GetMapping("/user")
public Principal user(Principal principal) {
return principal;
}
}
```
在上面的实现中,我们有两个端点:/api/hello和/api/user。前者返回一个简单的字符串,后者返回当前用户的Principal对象。
7. 测试应用程序
现在,您可以启动应用程序并使用以下步骤测试OAuth2和JWT:
- 获取访问令牌。使用以下curl命令以密码授权方式获取访问令牌:
```
curl -X POST \
-d 'grant_type=password&username=my-username&password=my-password' \
-H 'Authorization: Basic bXktY2xpZW50LWlkOm15LWNsaWVudC1zZWNyZXQ=' \
http://localhost:8080/oauth/token
```
在上面的命令中,my-username和my-password应该是您的用户名和密码,bXktY2xpZW50LWlkOm15LWNsaWVudC1zZWNyZXQ=应该是Base64编码的客户端ID和客户端密钥。
- 使用访问令牌访问API。使用以下curl命令使用JWT访问/api/hello端点:
```
curl -H 'Authorization: Bearer <access-token>' \
http://localhost:8080/api/hello
```
在上面的命令中,<access-token>应该是您在第一步中获取的访问令牌。
- 获取用户信息。使用以下curl命令使用JWT访问/api/user端点:
```
curl -H 'Authorization: Bearer <access-token>' \
http://localhost:8080/api/user
```
在上面的命令中,<access-token>应该是您在第一步中获取的访问令牌。
Spring Boot Security OAuth2 JWT完整示例
Spring Boot Security是一个非常流行的安全框架,可以帮助开发人员实现各种安全功能。其中,OAuth2和JWT是两个非常重要的安全技术,可以用于实现授权和认证。下面是一个基于Spring Boot Security的完整示例,演示如何使用OAuth2和JWT实现安全功能。
1. 创建一个Spring Boot项目
使用Spring Initializr创建一个新的Spring Boot项目,添加以下依赖:
- Spring Web
- Spring Security
- Spring Data JPA
- H2 Database
- Spring Security OAuth2
- jjwt
2. 添加配置文件
在application.properties文件中添加以下配置:
```
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.security.oauth2.client.registration.myapp.client-id=myapp
spring.security.oauth2.client.registration.myapp.client-secret=myappsecret
spring.security.oauth2.client.registration.myapp.scope=read,write
spring.security.oauth2.client.provider.myapp.authorization-uri=http://localhost:8080/oauth/authorize
spring.security.oauth2.client.provider.myapp.token-uri=http://localhost:8080/oauth/token
spring.security.oauth2.client.provider.myapp.user-info-uri=http://localhost:8080/userinfo
spring.security.oauth2.client.provider.myapp.user-name-attribute=name
```
这些配置将用于配置数据源、Hibernate、H2控制台和OAuth2。
3. 创建实体类和仓库
创建一个User实体类,用于表示用户信息:
```java
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false)
private String password;
@Column(nullable = false)
private String email;
// getters and setters
}
```
创建一个UserRepository接口,用于操作User实体类:
```java
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
}
```
4. 创建用户服务
创建一个UserService接口,用于定义获取用户和创建用户的方法:
```java
public interface UserService {
User createUser(String username, String password, String email);
Optional<User> getUserByUsername(String username);
}
```
创建一个UserServiceImpl实现UserService接口,用于实现上述方法:
```java
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public User createUser(String username, String password, String email) {
User user = new User();
user.setUsername(username);
user.setPassword(passwordEncoder.encode(password));
user.setEmail(email);
return userRepository.save(user);
}
@Override
public Optional<User> getUserByUsername(String username) {
return userRepository.findByUsername(username);
}
}
```
5. 配置Spring Security
创建一个WebSecurityConfig类,用于配置Spring Security:
```java
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth/**").permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(username -> userService.getUserByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found: " + username)))
.passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
```
这个配置类将所有请求都需要进行认证,但是允许OAuth2请求。同时,禁用了CSRF、表单登录、HTTP基本认证和会话管理。
6. 配置OAuth2
创建一个OAuth2Config类,用于配置OAuth2:
```java
@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserService userService;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("myapp")
.secret(passwordEncoder.encode("myappsecret"))
.authorizedGrantTypes("authorization_code", "refresh_token")
.scopes("read", "write")
.redirectUris("http://localhost:8081/login/oauth2/code/myapp");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.userDetailsService(username -> userService.getUserByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found: " + username)))
.accessTokenConverter(accessTokenConverter())
.pathMapping("/oauth/token", "/signin");
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("secret");
return converter;
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
}
```
这个配置类定义了一个OAuth2客户端,将授权码和刷新令牌作为授权类型,并允许读取和写入作用域。同时,定义了一个端点配置,将认证管理器、用户详情服务、访问令牌转换器和令牌存储配置到端点上。
7. 创建控制器
创建一个UserController类,用于处理用户相关的请求:
```java
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public User createUser(@RequestBody UserDto userDto) {
return userService.createUser(userDto.getUsername(), userDto.getPassword(), userDto.getEmail());
}
@GetMapping("/{username}")
public User getUser(@PathVariable String username) {
return userService.getUserByUsername(username)
.orElseThrow(() -> new NotFoundException("User not found: " + username));
}
}
```
这个控制器中定义了创建用户和获取用户的方法。
8. 创建JWT过滤器
创建一个JwtFilter类,用于在请求中验证JWT令牌:
```java
public class JwtFilter extends OncePerRequestFilter {
private static final String AUTHORIZATION_HEADER = "Authorization";
@Autowired
private JwtAccessTokenConverter accessTokenConverter;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authorizationHeader = request.getHeader(AUTHORIZATION_HEADER);
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
String token = authorizationHeader.substring(7);
Authentication authentication = accessTokenConverter.extractAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}
}
```
这个过滤器会从请求头中获取JWT令牌,并使用令牌转换器验证令牌。如果验证通过,则将用户认证信息存储到Spring Security上下文中。
9. 注册JWT过滤器
在WebSecurityConfig类中,添加以下配置:
```java
@Bean
public JwtFilter jwtFilter() {
return new JwtFilter();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class);
// ...
}
```
这个配置将JwtFilter注册到Spring Security过滤器链中。
10. 创建JWT工具类
创建一个JwtUtils类,用于生成和解析JWT令牌:
```java
public class JwtUtils {
public static final String SUBJECT = "myapp";
public static String generateToken(User user) {
Map<String, Object> claims = new HashMap<>();
claims.put("sub", SUBJECT);
claims.put("id", user.getId());
claims.put("username", user.getUsername());
claims.put("email", user.getEmail());
Date now = new Date();
Date expiration = new Date(now.getTime() + 60 * 60 * 1000);
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(expiration)
.signWith(SignatureAlgorithm.HS256, "secret")
.compact();
}
public static Long getUserIdFromToken(String token) {
Claims claims = Jwts.parser()
.setSigningKey("secret")
.parseClaimsJws(token)
.getBody();
return claims.get("id", Long.class);
}
}
```
这个工具类将用户信息存储到JWT令牌中,并使用HS256算法进行签名。
11. 创建DTO类
创建一个UserDto类,用于接收创建用户的请求:
```java
public class UserDto {
private String username;
private String password;
private String email;
// getters and setters
}
```
12. 测试
启动应用程序,并使用以下命令创建一个用户:
```
curl -X POST -H 'Content-Type: application/json' -d '{"username":"test","password":"test123","email":"test@example.com"}' http://localhost:8080/users
```
使用以下命令获取访问令牌:
```
curl -X POST -vu myapp:myappsecret http://localhost:8080/oauth/token -H 'Accept: application/json' -d 'grant_type=authorization_code&code={CODE}&redirect_uri=http://localhost:8081/login/oauth2/code/myapp'
```
将{CODE}替换为授权码,并将返回的访问令牌用于获取用户信息:
```
curl -H 'Authorization: Bearer {ACCESS_TOKEN}' http://localhost:8080/users/test
```
将{ACCESS_TOKEN}替换为访问令牌,在请求头中发送即可。
以上就是一个完整的Spring Boot Security OAuth2 JWT示例,演示了如何实现授权和认证。
相关推荐
![rar](https://img-home.csdnimg.cn/images/20210720083606.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)