SpringBoot整合OAuth2.0看完你就会了!

OAuth 2.0是一种开放的授权协议,它允许用户授权第三方应用访问其账户(或资源),而无需共享其用户账户凭据。在Spring Boot中,我们可以使用Spring Security的OAuth2.0模块来实现授权验证。

依赖引入

配置认证服务器

/**
 * @author Charles
 * @module springboot
 * @since 2023/6/19 16:30
 */

@Configuration
@EnableAuthorizationServer //开启认证服务器
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    //在 MyOAuth2Config 添加到容器了
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private MyUserDetailsService myUserDetailsService;

    @Autowired
    @Qualifier("jwtTokenStore")
    TokenStore jwtTokenStore;

    @Autowired
    JwtAccessTokenConverter jwtAccessTokenConverter;

    @Autowired
    TokenEnhancerChain tokenEnhancerChain;

    /**
     * 配置被允许访问此认证服务器的客户端详细信息
     * 1.内存管理
     * 2.数据库管理方式
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                //客户端名称
                .withClient("test-pc")
                //客户端密码
                .secret(passwordEncoder.encode("123456"))
                //资源id,商品资源
                .resourceIds("oauth2-server")
                //授权类型, 可同时支持多种授权类型
                .authorizedGrantTypes("authorization_code", "password", "implicit","client_credentials","refresh_token")
                //授权范围标识,哪部分资源可访问(all是标识,不是代表所有)
                .scopes("all")
                //false 跳转到授权页面手动点击授权,true 不用手动授权,直接响应授权码
                .autoApprove(false)
                //客户端回调地址
                .redirectUris("http://www.baidu.com/")
        ;
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        //密码模式需要配置认证管理器
        endpoints.authenticationManager(authenticationManager);
        //刷新令牌获取新令牌时需要
        endpoints.userDetailsService(myUserDetailsService);
        endpoints.tokenEnhancer(tokenEnhancerChain);
        //令牌管理策略
//        endpoints.tokenStore(tokenStore);
        //设置为jwt存储
        endpoints.tokenStore(jwtTokenStore);
        endpoints.accessTokenConverter(jwtAccessTokenConverter);
        //授权码管理策略,针对授权码模式有效,会将授权码放到 auth_code 表,授权后就会删除它
        //endpoints.authorizationCodeServices(jdbcAuthorizationCodeServices);
        DefaultTokenServices tokenService = getTokenStore(endpoints);
        endpoints.tokenServices(tokenService);
    }


    //配置TokenService参数
    private DefaultTokenServices getTokenStore(AuthorizationServerEndpointsConfigurer endpoints) {
        DefaultTokenServices tokenService = new DefaultTokenServices();
        tokenService.setTokenStore(endpoints.getTokenStore());
        tokenService.setSupportRefreshToken(true);
        tokenService.setClientDetailsService(endpoints.getClientDetailsService());
        tokenService.setTokenEnhancer(endpoints.getTokenEnhancer());
        //token有效期 1小时
        tokenService.setAccessTokenValiditySeconds(3600);
        //token刷新有效期 15天
        tokenService.setRefreshTokenValiditySeconds(3600 * 12 * 15);
        tokenService.setReuseRefreshToken(false);
        return tokenService;
    }

    /**
     * 解决访问/oauth/check_token 403的问题
     *
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        // 允许表单认证
        security
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("permitAll()")
                .allowFormAuthenticationForClients();

    }

配置资源服务器

/**
 * @author Charles
 * @module springboot
 * @since 2023/6/20 12:14
 */
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class OAuth2ResourceServer extends ResourceServerConfigurerAdapter {


    @Autowired
    @Qualifier("jwtTokenStore")
    TokenStore jwtTokenStore;

    @Override
    public void configure(HttpSecurity http) throws Exception {
          http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                //.authorizeRequests(request -> request.anyRequest().access("@checker.check(authentication,request)"))
                //.and()
                //放行
                .antMatchers("/oauth/**","/login/**","/logout/**", "/sse/**").permitAll()
                //其他路径需要role_admin
                .anyRequest().hasAnyAuthority("role_admin")
                .and()
                //表单提交放行
                .formLogin().permitAll()
                .and()
                //csrf关闭
                .exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {
              @Override
              public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                  System.out.println(accessDeniedException);
              }
          });

    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId("oauth2-server")
                 .tokenServices(tokenDefaultServices());
    }


    /**
     * 配置资源服务器如何校验token
     * 1. DefaultTokenServices
     * 如果认证服务器和资源服务器在同一个服务,则直接采用默认服务验证
     * 2.RemoteTokenServices
     * 当认证服务器和资源服务器不在同一个服务,要使用此服务器去远程认证服务器验证
     * @return
     */
    @Primary
    @Bean
    public DefaultTokenServices tokenDefaultServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(jwtTokenStore);
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }

//    @Primary
//    @Bean
//    public RemoteTokenServices tokenServices() {
//        //资源服务器去远程认证服务器验证 token 是否有效
//        final RemoteTokenServices tokenService = new RemoteTokenServices();
//        //请求认证服务器验证URL,注意:默认这个端点是拒绝访问的,要设置认证后可访问
//        tokenService.setCheckTokenEndpointUrl("http://localhost:8899/oauth/check_token");
//        //在认证服务器配置的客户端id
//        tokenService.setClientId("test-pc");
//        //在认证服务器配置的客户端密码
//        tokenService.setClientSecret("123456");
//        return tokenService;
//    }
}

token配置

/**
 * @author Charles
 * @module springboot
 * @since 2023/6/20 15:25
 */

@Configuration
public class JwtTokenStoreConfig {

    @Autowired
    private CustomTokenEnhancer customTokenEnhancer;


    @Value("${privateKey}")
    private String privateKey;

    @Value("${password}")
    private String password;

    @Value("${alias}")
    private String alias;

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter(){
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource(privateKey), password.toCharArray());
        jwtAccessTokenConverter.setKeyPair(keyStoreKeyFactory.getKeyPair(alias));
        return jwtAccessTokenConverter;
    }

    @Bean("jwtTokenStore")
    public TokenStore jwtTokenStore(){
        JwtTokenStore jwtTokenStore = new JwtTokenStore(jwtAccessTokenConverter());
        return jwtTokenStore;
    }


    @Bean
    public TokenEnhancerChain tokenEnhancerChain() {
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        List<TokenEnhancer> enhancers = new ArrayList<>();
        enhancers.add(jwtAccessTokenConverter());
        enhancers.add(customTokenEnhancer);
        //将自定义Enhancer加入EnhancerChain的delegates数组中
        enhancerChain.setTokenEnhancers(enhancers);
        return enhancerChain;
    }


    private static final KeyStore JKS_STORE;

    static {
        try {
            JKS_STORE = KeyStore.getInstance("jks");
        } catch (KeyStoreException e) {
            throw new RuntimeException("can not obtain jks keystore instance");
        }
    }

    @Bean
    @ConditionalOnMissingBean
    @SneakyThrows
    public JWKSource<SecurityContext> jwkSource() {
        ClassPathResource classPathResource = new ClassPathResource(privateKey);
        char[] pin = password.toCharArray();
        JKS_STORE.load(classPathResource.getInputStream(), pin);
        RSAKey rsaKey = RSAKey.load(JKS_STORE, alias, pin);
        JWKSet jwkSet = new JWKSet(rsaKey);
        return new ImmutableJWKSet<>(jwkSet);
    }

配置UserDetailsService

/**
 * @author Charles
 * @module springboot
 * @since 2023/6/20 11:47
 */
@Component
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return new User("admin", passwordEncoder.encode("123456"),
                AuthorityUtils.createAuthorityList("role_admin"));
    }
}

好了到此为止,以上就是springboot整合ouath2.0的主要代码啦,欢迎大家在评论区留言讨论!

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
Spring Boot可以与OAuth 2.0协议进行整合,实现授权和认证功能。下面是一些步骤: 1. 配置pom.xml文件,添加Spring Security OAuth2依赖。 ``` <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>2.3.7.RELEASE</version> </dependency> ``` 2. 配置application.properties文件,添加OAuth2配置。 ``` # OAuth2 configuration security.oauth2.client.client-id=client-id security.oauth2.client.client-secret=client-secret security.oauth2.client.access-token-uri=https://example.com/oauth/token security.oauth2.client.user-authorization-uri=https://example.com/oauth/authorize security.oauth2.client.scope=read,write security.oauth2.client.grant-type=authorization_code security.oauth2.resource.token-info-uri=https://example.com/oauth/check_token security.oauth2.resource.user-info-uri=https://example.com/userinfo ``` 3. 创建一个OAuth2客户端,用于向授权服务器发送请求并获取访问令牌。 ``` @Configuration @EnableOAuth2Sso public class OAuth2ClientConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/", "/login**", "/error**") .permitAll() .anyRequest() .authenticated() .and() .logout() .logoutSuccessUrl("/") .permitAll() .and() .csrf() .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); } @Bean public OAuth2RestTemplate oauth2RestTemplate(OAuth2ProtectedResourceDetails resource, OAuth2ClientContext context) { return new OAuth2RestTemplate(resource, context); } @Bean @ConfigurationProperties("security.oauth2.client") public OAuth2ProtectedResourceDetails oauth2RemoteResource() { return new AuthorizationCodeResourceDetails(); } @Bean public FilterRegistrationBean oauth2ClientFilterRegistration( OAuth2ClientContextFilter filter) { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(filter); registration.setOrder(-100); return registration; } } ``` 4. 创建一个OAuth2资源服务器,用于保护受保护的资源。 ``` @Configuration @EnableResourceServer public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/api/**") .authenticated(); } @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.resourceId("my-resource-id"); } } ``` 5. 创建一个授权服务器,用于颁发访问令牌。 ``` @Configuration @EnableAuthorizationServer public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserDetailsService userDetailsService; @Autowired private BCryptPasswordEncoder passwordEncoder; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("client-id") .secret(passwordEncoder.encode("client-secret")) .authorizedGrantTypes("authorization_code", "refresh_token") .scopes("read", "write") .accessTokenValiditySeconds(3600) .refreshTokenValiditySeconds(7200) .redirectUris("http://localhost:8080/login/oauth2/code/my-client"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager) .userDetailsService(userDetailsService); } } ``` 以上是整合OAuth2.0的一些步骤和代码示例。需要注意的是,OAuth2.0是一个复杂的协议,需要深入理解和熟练掌握。同时,需要根据实际业务需求进行相应的配置和开发。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值