1. 引入依赖
<?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.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springoauth</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springoauth</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</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>
2. 配置文件
oauth.grant_type=password
oauth.client_id=csdn
oauth.client_secret=123456
oauth.username=fisher
oauth.password=3652
oauth.jwt_key=jwtkey
3. 创建配置类
package com.example.springoauth.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
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.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
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;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import java.util.ArrayList;
import java.util.List;
@Configuration
@EnableAuthorizationServer
public class OauthServerConfig extends AuthorizationServerConfigurerAdapter {
/**
* 2小时
*/
private int accessTokenValiditySecond = 60 * 60 * 2;
/**
* 7 天
*/
private int refreshTokenValiditySecond = 60 * 60 * 24 * 7;
@Value("${oauth.grant_type}")
private String grant_type;
@Value("${oauth.client_id}")
private String client_id;
@Value("${oauth.client_secret}")
private String client_secret;
@Value("${oauth.username}")
private String username;
@Value("${oauth.password}")
private String password;
@Value("${oauth.jwt_key}")
private String jwtKey;
/**
* 添加客户端信息
*/
@Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
configurer.inMemory()
//client_id
.withClient(client_id)
//设置client_secret时必须要使用密码加密
.secret(passwordEncoder().encode(client_secret))
//设置权限类型,用密码,授权码,客户端,刷新的token
.authorizedGrantTypes("password", "authorization_code", "client_credentials", "refresh_token")
//权限为所有人
.scopes("all")
// 自动授权配置
.autoApprove(true)
//accesstoken有效期
.accessTokenValiditySeconds(accessTokenValiditySecond)
//refreshtoken有效期
.refreshTokenValiditySeconds(refreshTokenValiditySecond)
// 单点登录时配置
.redirectUris("https://www.baidu.com");
}
/**
* 定义授权和令牌端点和令牌服务
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpointsConfigurer) {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
List<TokenEnhancer> delegates = new ArrayList<>();
//配置jwt内容增强器
delegates.add(jwtTokenEnhancer());
//配置增强TOKEN
delegates.add(accessTokenJwtConverter());
tokenEnhancerChain.setTokenEnhancers(delegates);
//刷新令牌时需要的认证管理和用户信息来源
endpointsConfigurer.authenticationManager(authenticationManager())
//默认获取token只能POST方法
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
//一定要指定userDetailsService,不然refreshtoken会提示IllegalStateException, UserDetailsService is required.
.userDetailsService(userDetailsService())
//使用jwt的tokenstore存储令牌
.tokenStore(jwtTokenStore())
//配置token的内容增强器
.tokenEnhancer(tokenEnhancerChain);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
//允许表单认证
oauthServer.allowFormAuthenticationForClients();
//允许 check_token 访问
oauthServer.checkTokenAccess("permitAll()");
}
@Bean
AuthenticationManager authenticationManager() {
AuthenticationManager authenticationManager = new AuthenticationManager() {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
return daoAuhthenticationProvider().authenticate(authentication);
}
};
return authenticationManager;
}
@Bean
public AuthenticationProvider daoAuhthenticationProvider() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
//添加用户信息
daoAuthenticationProvider.setUserDetailsService(userDetailsService());
daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
return daoAuthenticationProvider;
}
/**
* 设置用户信息
*/
@Bean
UserDetailsService userDetailsService() {
InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager();
//这里可以从数据库中获取多个用户,循环调用createUser方法添加到一个Map中
userDetailsService.createUser(User.withUsername(username).password(passwordEncoder().encode(password))
.authorities("ROLE_USER").build());
return userDetailsService;
}
@Bean
PasswordEncoder passwordEncoder() {
// 加密方式
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder;
}
@Bean
public TokenStore jwtTokenStore() {
return new JwtTokenStore(accessTokenJwtConverter());
}
/**
* JWT
*/
@Bean
public JwtAccessTokenConverter accessTokenJwtConverter() {
JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
// 配置jwt使用的密钥
accessTokenConverter.setSigningKey(jwtKey);
return accessTokenConverter;
}
/**
* token enhance
*/
@Bean
public JwtTokenEnhancer jwtTokenEnhancer() {
return new JwtTokenEnhancer();
}
}
4. 创建token增强器
- 可以添加需要传到服务中的信息
package com.example.springoauth.config;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import java.util.HashMap;
import java.util.Map;
public class JwtTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
String username = authentication.getUserAuthentication().getName();
//可以从数据库中获取
Map<String, Object> map = new HashMap<>();
map.put("userName", username);
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(map);
return accessToken;
}
}
5. 启动类
package com.example.springoauth;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class OauthApplication {
public static void main(String[] args) {
SpringApplication.run(OauthApplication.class, args);
}
}
6. 获取token
- 调用接口http://localhost:8080/oauth/token
7. 刷新token
- 调用接口http://localhost:8080/oauth/token,传入refresh_token的值