SpringBoot使用OAuth2密码模式+JWT搭建认证服务器

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的值

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_40977118/article/details/116757371