前言
在当今数字化转型的时代,企业级应用系统的安全认证授权变得尤为重要。Spring Security作为Java生态中最成熟的安全框架之一,结合OAuth2协议,能够为企业构建强大而灵活的身份认证和授权体系。本文将从零开始,详细介绍如何基于Spring Security和OAuth2协议构建一个完整的企业级认证授权系统。
什么是Spring Security + OAuth2
Spring Security简介
Spring Security是Spring生态系统中的安全框架,提供了全面的安全服务,包括认证、授权、防护攻击等核心功能。它通过过滤器链的方式拦截HTTP请求,对用户身份进行验证,并根据配置的权限规则控制访问。
OAuth2协议概述
OAuth2是一个开放的授权标准,允许第三方应用在用户授权的前提下访问用户资源。它定义了四种授权模式:
- 授权码模式(Authorization Code)
- 隐藏式模式(Implicit)
- 密码模式(Resource Owner Password Credentials)
- 客户端凭证模式(Client Credentials)
系统架构设计
整体架构图
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 前端应用 │ │ API网关 │ │ 认证服务 │
│ │ │ │ │ │
│ 浏览器 │───▶│ Zuul/ Gateway │───▶│ Spring Security │
│ │ │ │ │ │
└─────────────┘ └─────────────┘ └─────────────┘
│
▼
┌─────────────┐
│ 资源服务 │
│ │
│ Spring Boot│
│ │
└─────────────┘
核心组件说明
- 认证服务器:负责用户认证和令牌发放
- 资源服务器:保护受保护的资源
- 客户端应用:请求访问受保护资源的应用
- API网关:统一入口,处理路由和安全控制
项目初始化与依赖配置
Maven依赖配置
<?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
http://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.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>oauth2-auth-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>oauth2-auth-server</name>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.3</spring-cloud.version>
</properties>
<dependencies>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- OAuth2 Server -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>0.4.0</version>
</dependency>
<!-- JWT Support -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- Spring Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Database -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
用户认证系统实现
用户实体类设计
// User.java
package com.example.auth.model;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.List;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String username;
@Column(nullable = false)
private String password;
@Column(unique = true, nullable = false)
private String email;
private Boolean enabled = true;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private List<Role> roles;
// Constructors
public User() {}
public User(String username, String password, String email) {
this.username = username;
this.password = password;
this.email = email;
this.createdAt = LocalDateTime.now();
this.updatedAt = LocalDateTime.now();
}
// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public Boolean getEnabled() { return enabled; }
public void setEnabled(Boolean enabled) { this.enabled = enabled; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
public LocalDateTime getUpdatedAt() { return updatedAt; }
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
public List<Role> getRoles() { return roles; }
public void setRoles(List<Role> roles) { this.roles = roles; }
}
角色实体类设计
// Role.java
package com.example.auth.model;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name = "roles")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String name;
@Column(length = 1000)
private String description;
@ManyToMany(mappedBy = "roles")
private List<User> users;
// Constructors
public Role() {}
public Role(String name) {
this.name = name;
}
public Role(String name, String description) {
this.name = name;
this.description = description;
}
// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public List<User> getUsers() { return users; }
public void setUsers(List<User> users) { this.users = users; }
}
Spring Security配置
安全配置类
// SecurityConfig.java
package com.example.auth.config;
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.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(oidc -> oidc
.providerConfigurationEndpoint(providerConfigurationEndpoint ->
providerConfigurationEndpoint
.authenticationManager(authenticationManager)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.requireProofKey(true)
)
);
http
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt.decoder(jwtDecoder()))
)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/oauth2/**", "/login", "/logout").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
@Bean
public JwtDecoder jwtDecoder() {
// 实现JWT解码器
return new CustomJwtDecoder();
}
}
JWT解码器实现
// CustomJwtDecoder.java
package com.example.auth.config;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtException;
import java.time.Instant;
import java.util.Date;
import java.util.Map;
public class CustomJwtDecoder implements JwtDecoder {
private final String secretKey = "your-secret-key-for-jwt-encoding";
@Override
public Jwt decode(String token) throws JwtException {
try {
Jws<Claims> claimsJws = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token);
Claims claims = claimsJws.getBody();
Instant issuedAt = claims.getIssuedAt().toInstant();
Instant expiresAt = claims.getExpiration().toInstant();
Map<String, Object> headers = claimsJws.getHeader();
Map<String, Object> claimsMap = claims;
return new Jwt(token, issuedAt, expiresAt, headers, claimsMap);
} catch (Exception ex) {
throw new JwtException("Invalid JWT token", ex);
}
}
}
OAuth2认证服务器配置
授权服务器配置
// AuthorizationServerConfig.java
package com.example.auth.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
import org.springframework.security.web.SecurityFilterChain;
import java.time.Duration;
import java.util.UUID;
@Configuration
@Order(1)
public class AuthorizationServerConfig {
@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(oidc -> oidc
.providerConfigurationEndpoint(providerConfigurationEndpoint ->
providerConfigurationEndpoint
.authenticationManager(authenticationManager)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.requireProofKey(true)
)
);
return http.build();
}
@Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("web-client")
.clientSecret("{noop}web-secret") // 使用{noop}表示不加密
.redirectUri("http://localhost:3000/oauth2/callback")
.redirectUri("http://localhost:8080/login/oauth2/code/my-app")
.scope("read")
.scope("write")
.scope(OidcScopes.OPENID)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.tokenSettings(TokenSettings.builder()
.accessTokenTimeToLive(Duration.ofHours(1))
.refreshTokenTimeToLive(Duration.ofDays(30))
.reuseRefreshTokens(false)
.build())
.clientSettings(ClientSettings.builder()
.requireAuthorizationConsent(true)
.build())
.build();
return new InMemoryRegisteredClientRepository(registeredClient);
}
}
用户认证服务实现
用户服务接口
// UserService.java
package com.example.auth.service;
import com.example.auth.model.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import java.util.List;
import java.util.Optional;
public interface UserService extends UserDetailsService {
User saveUser(User user);
Optional<User> findByUsername(String username);
Optional<User> findByEmail(String email);
List<User> findAllUsers();
void deleteUser(Long id);
User updateUser(Long id, User userDetails);
}
用户服务实现
// UserServiceImpl.java
package com.example.auth.service.impl;
import com.example.auth.model.User;
import com.example.auth.repository.UserRepository;
import com.example.auth.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public User saveUser(User user) {
// 加密密码
user.setPassword(passwordEncoder.encode(user.getPassword()));
return userRepository.save(user);
}
@Override
public Optional<User> findByUsername(String username) {
return userRepository.findByUsername(username);
}
@Override
public Optional<User> findByEmail(String email) {
return userRepository.findByEmail(email);
}
@Override
public List<User> findAllUsers() {
return userRepository.findAll();
}
@Override
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
@Override
public User updateUser(Long id, User userDetails) {
User user = userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("User not found"));
user.setUsername(userDetails.getUsername());
user.setEmail(userDetails.getEmail());
if (userDetails.getPassword() != null && !userDetails.getPassword().isEmpty()) {
user.setPassword(passwordEncoder.encode(userDetails.getPassword()));
}
return userRepository.save(user);
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found: " + username));
return org.springframework.security.core.userdetails.User.builder()
.username(user.getUsername())
.password(user.getPassword())
.authorities(user.getRoles().stream()
.flatMap(role -> role.getUsers().stream())
.map(role -> "ROLE_" + role.getName())
.toArray(String[]::new))
.accountExpired(false)
.accountLocked(false)
.credentialsExpired(false)
.disabled(!user.getEnabled())
.build();
}
}
JWT令牌管理
JWT工具类
// JwtTokenUtil.java
package com.example.auth.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
@Component
public class JwtTokenUtil implements Serializable {
private static final long serialVersionUID = -2550185165626007488L;
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
public String getUsernameFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}
private Claims getAllClaimsFromToken(String token) {
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
}
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return createToken(claims, userDetails.getUsername());
}
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + expiration * 1000))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = getUsernameFromToken(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
}
认证控制器
// AuthController.java
package com.example.auth.controller;
import com.example.auth.model.User;
import com.example.auth.service.UserService;
import com.example.auth.util.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/auth")
@CrossOrigin
public class AuthController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserService userService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest loginRequest) throws Exception {
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
loginRequest.getUsername(),
loginRequest.getPassword()
)
);
} catch (BadCredentialsException e) {
throw new Exception("Incorrect username or password", e);
} catch (DisabledException e) {
throw new Exception("User account is disabled", e);
}
final UserDetails userDetails = userService.loadUserByUsername(loginRequest.getUsername());
final String token = jwtTokenUtil.generateToken(userDetails);
Map<String, Object> response = new HashMap<>();
response.put("token", token);
response.put("user", userDetails.getUsername());
return ResponseEntity.ok(response);
}
@PostMapping("/register")
public ResponseEntity<?> register(@RequestBody User user) {
try {
User existingUser = userService.findByUsername(user.getUsername()).orElse(null);
if (existingUser != null) {
return ResponseEntity.badRequest().body("Username already exists");
}
existingUser = userService.findByEmail(user.getEmail()).orElse(null);
if (existingUser != null) {
return ResponseEntity.badRequest().body("Email already exists");
}
User savedUser = userService.saveUser(user);
return ResponseEntity.ok(savedUser);
} catch (Exception e) {
return ResponseEntity.badRequest().body("Registration failed: " + e.getMessage());
}
}
@GetMapping("/validate")
public ResponseEntity<?> validateToken(@RequestParam String token) {
try {
if (jwtTokenUtil.validateToken(token,
userService.loadUserByUsername(jwtTokenUtil.getUsernameFromToken(token)))) {
return ResponseEntity.ok("Token is valid");
} else {
return ResponseEntity.status(401).body("Token is invalid");
}
} catch (Exception e) {
return ResponseEntity.status(401).body("Token validation failed: " + e.getMessage());
}
}
}
// LoginRequest.java
package com.example.auth.controller;
public class LoginRequest {
private String username;
private String password;
// Constructors
public LoginRequest() {}
public LoginRequest(String username, String password) {
this.username = username;
this.password = password;
}
// Getters and Setters
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}
权限控制实现
基于角色的权限控制
// RoleBasedAccessControl.java
package com.example.auth.security;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.List;
@Component
public class RoleBasedAccessControl {
public boolean hasRole(Authentication authentication, String role) {
if (authentication == null || authentication.getAuthorities() == null) {
return false;
}
return authentication.getAuthorities().stream()
.anyMatch(authority -> authority.getAuthority().equals("ROLE_" + role));
}
public boolean hasAnyRole(Authentication authentication, List<String> roles) {
if (authentication == null || authentication.getAuthorities() == null) {
return false;
}
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
return roles.stream()
.anyMatch(role -> authorities.stream()
.anyMatch(authority -> authority.getAuthority().equals("ROLE_" + role)));
}
public void checkAccess(Authentication authentication, String requiredRole) {
if (!hasRole(authentication, requiredRole)) {
throw new AccessDeniedException("Access denied. Required role: " + requiredRole);
}
}
}
自定义权限注解
// HasRole.java
package com.example.auth.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface HasRole {
String value();
}
权限控制切面
// RoleAuthorizationAspect.java
package com.example.auth.aspect;
import com.example.auth.annotation.HasRole;
import com.example.auth.security.RoleBasedAccessControl;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class RoleAuthorizationAspect {
@Autowired
private RoleBasedAccessControl roleBasedAccessControl;
@Around("@annotation(hasRole)")
public Object checkRole(ProceedingJoinPoint joinPoint, HasRole hasRole) throws Throwable {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !roleBasedAccessControl.hasRole(authentication, hasRole.value())) {
throw new RuntimeException("Access denied. Required role: " + hasRole.value());
}
return joinPoint.proceed();
}
}
单点登录(SSO)集成
SSO配置类
// SsoConfig.java
package com.example.auth.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientManager;
@Configuration
public class SsoConfig {
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build();
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
}
SSO控制器
// SsoController.java
package com.example.auth.controller;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework
评论 (0)