Java中的单点登录实现:OAuth2与JWT
大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们来探讨在Java中如何使用OAuth2与JWT实现单点登录(SSO)。
一、单点登录概述
单点登录(Single Sign-On, SSO)是一种认证机制,允许用户在多个应用系统中使用一个账户登录一次,即可访问所有相互信任的应用系统。OAuth2和JWT是实现单点登录的两个重要技术。
二、OAuth2简介
OAuth2(Open Authorization)是一个用于资源授权的开放标准,允许第三方应用以有限的访问权限访问用户的资源,而无需将用户的凭据暴露给第三方。
三、JWT简介
JWT(JSON Web Token)是一种紧凑且自包含的令牌格式,用于在各方之间传递信息。JWT可以通过数字签名验证其真实性,且可以携带用户的认证信息。
四、Spring Boot项目配置
首先,我们需要创建一个Spring Boot项目,并添加必要的依赖。以下是Maven配置:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
五、OAuth2认证服务器配置
我们使用Spring Security OAuth2来配置认证服务器,生成和验证JWT令牌。
1. 创建授权服务器配置
package cn.juwatech.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client-id")
.secret("{noop}client-secret")
.authorizedGrantTypes("password", "refresh_token")
.scopes("read", "write")
.accessTokenValiditySeconds(3600)
.refreshTokenValiditySeconds(7200);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.tokenStore(tokenStore()).accessTokenConverter(accessTokenConverter());
}
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("secret-key");
return converter;
}
}
2. 创建资源服务器配置
package cn.juwatech.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId("resource-id").stateless(true);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.antMatchers("/").permitAll();
}
}
六、定义用户服务
定义用户服务类,用于处理用户的认证和授权:
package cn.juwatech.service;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.Collections;
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if ("user".equals(username)) {
return new User("user", "{noop}password", Collections.emptyList());
}
throw new UsernameNotFoundException("User not found");
}
}
七、实现RESTful接口
实现一个简单的RESTful接口,只有通过认证的用户才能访问:
package cn.juwatech.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api")
public class ApiController {
@GetMapping("/hello")
public String hello() {
return "Hello, authenticated user!";
}
}
八、配置安全配置类
配置Spring Security以支持OAuth2和JWT:
package cn.juwatech.config;
import cn.juwatech.service.CustomUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth/token").permitAll()
.anyRequest().authenticated();
}
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
九、测试单点登录
启动Spring Boot应用,使用Postman测试OAuth2授权和JWT令牌。
-
获取令牌:
- 请求:
POST /oauth/token
- 请求体:
grant_type=password&username=user&password=password&client_id=client-id&client_secret=client-secret
- 响应:返回包含访问令牌的JSON对象。
- 请求:
-
访问受保护的资源:
- 请求:
GET /api/hello
- 头部:
Authorization: Bearer {access_token}
- 响应:
Hello, authenticated user!
- 请求:
总结
本文介绍了如何使用Spring Boot构建一个基于OAuth2和JWT的单点登录系统。通过配置授权服务器、资源服务器、用户服务和安全配置,我们实现了一个简单且安全的RESTful微服务。
本文著作权归聚娃科技微赚淘客系统开发者团队,转载请注明出处!