Spring cloud + oauth2 to achieve micro service authentication, too simple!

Old gun says Java 2021-01-20 22:57:38
spring cloud oauth2 oauth achieve


Welcome to WeChat search official account 【java edition web project 】 Access to resources :java Learning video / Design pattern notes / Algorithm manual /java project

One 、SpringCloud Security brief introduction

​ Spring Cloud Security Provides a set of primitives , For building secure applications and services , And it's easy to operate . It can be outside ( Or concentrate ) A declarative model with a large number of configurations helps to implement large-scale collaborative remote component systems , There is usually a central identity management service . It's also very easy to Cloud Foundry And other service platforms . stay Spring Boot and Spring Security OAuth2 On the basis of , You can quickly create systems that implement common patterns , Such as single sign on , Token relay and token exchange .

function :

  • from Zuul Front end to back end service relay in agent SSO token
  • Relay token between resource servers
  • send Feign The client behaves like OAuth2RestTemplate( Get token, etc ) Interceptor
  • stay Zuul Configure downstream authentication in the proxy

Two 、 Single sign on Implementation

1、 stay SpringCloud—— Registration and discovery of services Eureka On the basis of

add to spring-security Support :

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

Add the configuration :

server:
port: 8082
spring:
application:
name: eureka-client
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8081/eureka/
# fetch-registry: false
# register-with-eureka: false
# Configuration of security authentication
security:
basic:
enabled: true

2、 Start the project , Browser access :http://localhost:8082/test

Enter the user name and password for authentication , The user is called user, The password will be output to the console when the program starts , Pictured :

After successful login, the browser will display :

test=============8082

3、 ... and 、 To configure MySQL Database authentication

1、 Add dependencies :

<?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>
<groupId>com.example.demo.security</groupId>
<artifactId>security-oauth2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>security-oauth2</name>
<parent>
<groupId>com.example.demo</groupId>
<artifactId>springcloud-security</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-velocity</artifactId>
<version>1.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

2、 Add configuration file :

server:
port: 8081
spring:
application:
name: security-oauth2
datasource:
url: jdbc:mysql://127.0.0.1:3306/alan_oauth?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=true&autoReconnect=true
username: root
password: admin
driver-class-name: com.mysql.jdbc.Driver
security:
basic:
enabled: false

3、 relevant config The configuration file

Create authorization configuration information class OAuthSecurityConfig.java, Statement TokenStore The implementation and ClientDetails The implementation of the .

package com.example.demo.security.config;
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.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
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.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import javax.sql.DataSource;
import java.util.concurrent.TimeUnit;
/**
* route :com.example.demo.security.config
* Class name :
* function :《 Describe... In one sentence 》
* remarks :
* founder :typ
* Creation time :2018/9/26 14:25
* Modifier :
* Revise notes :
* Modification time :
*/
@Configuration
public class OAuthSecurityConfig extends AuthorizationServerConfigurerAdapter{
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private DataSource dataSource;
@Bean
public TokenStore tokenStore(){
return new JdbcTokenStore(dataSource);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
endpoints.tokenStore(tokenStore());
// To configure TokenServices Parameters
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(endpoints.getTokenStore());
tokenServices.setSupportRefreshToken(false);
tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
tokenServices.setAccessTokenValiditySeconds( (int) TimeUnit.DAYS.toSeconds(30)); // 30 God
endpoints.tokenServices(tokenServices);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
//oauthServer.checkTokenAccess("isAuthenticated()");
oauthServer.checkTokenAccess("permitAll()");
oauthServer.allowFormAuthenticationForClients();
}
@Bean
public ClientDetailsService clientDetails() {
return new JdbcClientDetailsService(dataSource);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetails());
clients.inMemory()
.withClient("client")
.secret("secret")
.authorizedGrantTypes("authorization_code")
.scopes("app");
}
}

Security service configuration class OAuthWebConfig.java

package com.example.demo.security.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
* route :com.example.demo.security.config
* Class name :
* function :《 Describe... In one sentence 》
* remarks :
* founder :typ
* Creation time :2018/9/26 14:22
* Modifier :
* Revise notes :
* Modification time :
*/
@Configuration
public class OAuthWebConfig extends WebSecurityConfigurerAdapter{
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/favor.ico");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
}
}

Customize provider Calling class SsoAuthProvider.java

package com.example.demo.security.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import java.util.Collections;
/**
* route :com.example.demo.security.config
* Class name :
* function :《 Describe... In one sentence 》
* remarks :
* founder :typ
* Creation time :2018/9/26 14:33
* Modifier :
* Revise notes :
* Modification time :
*/
@Component
public class SsoAuthProvider implements AuthenticationProvider{
private static final Logger log = LoggerFactory.getLogger(SsoAuthProvider.class);
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
log.info(" Customize provider call ");
//// Return to one Token Object indicates successful login
return new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), Collections.<GrantedAuthority>emptyList());
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}

4、 Need a redirected controller class

package com.example.demo.security.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.SessionAttributes;
import java.util.Map;
/**
* route :com.example.demo.security.controller
* Class name :
* function :《 Describe... In one sentence 》
* remarks :
* founder :typ
* Creation time :2018/9/26 14:30
* Modifier :
* Revise notes :
* Modification time :
*/
@RestController
@SessionAttributes("authorizationRequest")
public class ErrorController {
private static final Logger log = LoggerFactory.getLogger(ErrorController.class);
@RequestMapping("/oauth/error")
public String error(@RequestParam Map<String, String> parameters){
String url = parameters.get("redirect_uri");
log.info(" Redirect : {}", url);
return "redirect:" + url + "?error=1";
}
}

5、 Start the class to add comments @EnableAuthorizationServer

package com.example.demo.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import java.util.Arrays;
@SpringBootApplication
@EnableAuthorizationServer
public class SecurityOauth2Application {
public static void main(String[] args) {
SpringApplication.run(SecurityOauth2Application.class, args);
}
@Autowired
private AuthenticationProvider authenticationProvider;
@Bean
public AuthenticationManager authenticationManager(){
return new ProviderManager(Arrays.asList(authenticationProvider));
}
}

6、 Create a database and related tables

# Host: 127.0.0.1 (Version 5.7.21)
# Date: 2018-09-26 15:17:51
# Generator: MySQL-Front 6.0 (Build 2.20)
#
# Structure for table "clientdetails"
#
DROP TABLE IF EXISTS `clientdetails`;
CREATE TABLE `clientdetails` (
`appId` varchar(128) NOT NULL,
`resourceIds` varchar(256) DEFAULT NULL,
`appSecret` varchar(256) DEFAULT NULL,
`scope` varchar(256) DEFAULT NULL,
`grantTypes` varchar(256) DEFAULT NULL,
`redirectUrl` varchar(256) DEFAULT NULL,
`authorities` varchar(256) DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL,
`refresh_token_validity` int(11) DEFAULT NULL,
`additionalInformation` varchar(4096) DEFAULT NULL,
`autoApproveScopes` varchar(256) DEFAULT NULL,
PRIMARY KEY (`appId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
#
# Data for table "clientdetails"
#
#
# Structure for table "oauth_access_token"
#
DROP TABLE IF EXISTS `oauth_access_token`;
CREATE TABLE `oauth_access_token` (
`token_id` varchar(256) DEFAULT NULL,
`token` blob,
`authentication_id` varchar(128) NOT NULL,
`user_name` varchar(256) DEFAULT NULL,
`client_id` varchar(256) DEFAULT NULL,
`authentication` blob,
`refresh_token` varchar(256) DEFAULT NULL,
PRIMARY KEY (`authentication_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
#
# Data for table "oauth_access_token"
#
#
# Structure for table "oauth_approvals"
#
DROP TABLE IF EXISTS `oauth_approvals`;
CREATE TABLE `oauth_approvals` (
`userId` varchar(256) DEFAULT NULL,
`clientId` varchar(256) DEFAULT NULL,
`scope` varchar(256) DEFAULT NULL,
`status` varchar(10) DEFAULT NULL,
`expiresAt` datetime DEFAULT NULL,
`lastModifiedAt` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
#
# Data for table "oauth_approvals"
#
#
# Structure for table "oauth_client_details"
#
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
`client_id` varchar(128) NOT NULL,
`resource_ids` varchar(256) DEFAULT NULL,
`client_secret` varchar(256) DEFAULT NULL,
`scope` varchar(256) DEFAULT NULL,
`authorized_grant_types` varchar(256) DEFAULT NULL,
`web_server_redirect_uri` varchar(256) DEFAULT NULL,
`authorities` varchar(256) DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL,
`refresh_token_validity` int(11) DEFAULT NULL,
`additional_information` varchar(4096) DEFAULT NULL,
`autoapprove` varchar(256) DEFAULT NULL,
PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
#
# Data for table "oauth_client_details"
#
INSERT INTO `oauth_client_details` VALUES ('client',NULL,'secret','app','authorization_code','http://www.baidu.com',NULL,NULL,NULL,NULL,NULL);
#
# Structure for table "oauth_client_token"
#
DROP TABLE IF EXISTS `oauth_client_token`;
CREATE TABLE `oauth_client_token` (
`token_id` varchar(256) DEFAULT NULL,
`token` blob,
`authentication_id` varchar(128) NOT NULL,
`user_name` varchar(256) DEFAULT NULL,
`client_id` varchar(256) DEFAULT NULL,
PRIMARY KEY (`authentication_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
#
# Data for table "oauth_client_token"
#
#
# Structure for table "oauth_code"
#
DROP TABLE IF EXISTS `oauth_code`;
CREATE TABLE `oauth_code` (
`code` varchar(256) DEFAULT NULL,
`authentication` blob
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
#
# Data for table "oauth_code"
#
#
# Structure for table "oauth_refresh_token"
#
DROP TABLE IF EXISTS `oauth_refresh_token`;
CREATE TABLE `oauth_refresh_token` (
`token_id` varchar(256) DEFAULT NULL,
`token` blob,
`authentication` blob
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
#
# Data for table "oauth_refresh_token"
#

stay oauth_client_details Add a piece of data to the table

INSERT INTO `oauth_client_details` VALUES ('client',NULL,'secret','app','authorization_code','http://www.baidu.com',NULL,NULL,NULL,NULL,NULL);

Start the project , Browser access :

http://localhost:8081/oauth/authorize?client_id=client&response_type=code&redirect_uri=http://www.baidu.com

Click on Authorize Will jump to Baidu page , Because the database configuration is Baidu page .

Four 、OAuth The idea of

OAuth stay " client " And " Service provider " Between , An authorization layer is set up (authorization layer)." client " Can't log in directly " Service provider ", Only login authorization layer , To distinguish users from clients ." client " Token used by login authorization layer (token), Different password from user . Users can log in , Specify the permission range and validity period of the authorization layer token .

" client " After logging into the authorization layer ," Service provider " Based on the token's permission range and validity , towards " client " Open user stored data .

OAuth 2.0 Operation flow :

(A) After the user opens the client , Client requires authorization from user .

(B) User agrees to authorize client .

(C) The client uses the authorization obtained in the previous step , Request token from authentication server .

(D) After the authentication server authenticates the client , Confirm no mistake , Agree to issue token .

(E) Client use token , Request resources from resource server .

(F) Resource server confirms that the token is correct , Agree to open resources to clients .

In the six steps above ,B Is the key , That is, how can the user authorize the client . With this authorization , The client can get the token , And then get the resources by token .

5、 ... and 、 Client authorization mode

The client must be authorized by the user (authorization grant), To get a token (access token).

OAuth 2.0 Four authorization methods are defined :

  • Authorization code mode (authorization code)
  • Simplified mode (implicit)
  • Password mode (resource owner password credentials)
  • Client mode (client credentials)

1、 Authorization code mode

Authorization code mode (authorization code) Is the most complete function 、 The most rigorous authorization mode . Its characteristic is through the background server of the client , And " Service provider " Authentication server of .

Steps are as follows :

(A) User access client , The latter will direct the former to the authentication server .

(B) User chooses whether to grant client authorization .

(C) Suppose the user gives authorization , The authentication server directs users to the specified " Redirect URI"(redirection URI), With an authorization code .

(D) Client receives authorization code , Attach the previous " Redirect URI", Request token from authentication server . This step is done on the background server of the client , Invisible to users .

(E) Authentication server checked authorization code and redirection URI, After confirmation , Send access token to client (access token) And update token (refresh token).

2、 Simplified mode

Simplified mode (implicit grant type) Servers that do not pass through third-party applications , Request token directly from authentication server in browser , Skip the " Authorization code " This step , Hence the name . All steps in browser , The token is visible to the visitor , And the client does not need authentication .

Steps are as follows :

(A) Clients direct users to authentication servers .

(B) The user decides whether to authorize the client .

(C) Suppose the user gives authorization , The authentication server directs the user to the specified " Redirect URI", And in URI Of Hash Part contains access tokens .

(D) Browser makes request to resource server , It does not include the last received Hash value .

(E) Resource server returns a web page , The code contained in it can be obtained Hash Token in value .

(F) The browser executes the script obtained in the previous step , Extract token .

(G) Browser sends token to client .

3、 Password mode

Password mode (Resource Owner Password Credentials Grant) in , Users provide their own user name and password to the client . Clients use this information , towards " Service provider " Asking for authorization .

In this mode , The user must give his password to the client , But the client must not store the password . This is usually used when the user has a high trust in the client , For example, the client is part of the operating system , Or produced by a famous company . And the authentication server can only execute when other authorization modes cannot , To consider using this pattern .

Steps are as follows :

(A) User provides user name and password to client .

(B) Client sends user name and password to authentication server , Request token for the backer .

(C) After confirming that the authentication server is correct , Provide access token to client .

4、 Client mode

Client mode (Client Credentials Grant) Client in its own name , Not in the name of the user , towards " Service provider " authentication . Strictly speaking , Client mode does not belong to OAuth Problems to be solved by the framework . In this mode , Users register directly with clients , Client requests in its own name " Service provider " Provide services , In fact, there is no authorization problem .

Steps are as follows :

(A) Client authenticates to authentication server , And requires an access token .

(B) After confirming that the authentication server is correct , Provide access token to client .

6、 ... and 、 Update token

If the user visits , Client's " The access token " It's overdue , You need to use " Update token " Apply for a new access token .

The client sends the update token HTTP request , Contains the following parameters :

  • granttype: Indicates the authorization mode used , The value here is fixed to "refreshtoken", Will options .
  • refresh_token: Indicates an update token received earlier , Will options .
  • scope: Indicates the authorization scope of the application , It is not allowed to go beyond the scope of the last application , If this parameter is omitted , It means the same as the last time .
author : Programmer base

source :https://www.pianshen.com/arti...

Recent hot article recommends :

SpringCloud Micro service e-commerce project tutorial

版权声明
本文为[Old gun says Java]所创,转载请带上原文链接,感谢
https://javamana.com/2021/01/20210120225536559F.html

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云