“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。

开发人员知道保护Web应用程序安全可能会很麻烦。 正确地做是很难的。 最糟糕的是,“正确”是一个移动的目标。 安全协议会更改。 在依赖项中发现漏洞,并发布了补丁程序。 必须生成大量通常很复杂的样板代码。 在过去的十年中,软件即服务的范式已经泛滥成灾,尽管我喜欢和下一个开发人员一样重新发明轮子(因为显然,我会比他们雇用的yahoo更好地编写它),但是安全是一个领域在这里,我很乐意将这项工作分担给专家。 输入Okta。

在本教程中,您将使用Spring Boot来构建带有用户注册系统和登录系统的简单Web应用程序。 它具有以下功能:

  • 登录和注册页面
  • 密码重置工作流程
  • 根据组成员身份限制访问

下载Spring Boot Web App示例项目

您首先需要的是免费的Okta帐户。 如果您还没有,请前往developer.okta.com并注册!

下一步是从GitHub下载本教程的示例项目。

git clone https://github.com/oktadeveloper/okta-spring-simple-app-example.git spring-app

该项目使用Gradle作为构建工具以及Thymeleaf模板系统。

运行初始Web应用

从GitHub存储库下载示例代码后,使用以下git命令git checkout tags/Start Start标记: git checkout tags/Start

目前,该应用程序尚未受到任何保护。 没有启用任何授权或身份验证(即使build.gradle文件中包含必需的依赖build.gradle )。 继续并运行示例,方法是打开一个终端,然后从项目根目录运行命令./gradlew bootRunbootRun命令是Gradle Spring Boot插件提供的任务,已添加到build.gradle中的build.gradle文件中。部分)。

在您喜欢的浏览器中导航到http://localhost:8080 ,您应该看到以下内容:


如果您点击“受限”按钮:


为您的Spring Boot + Spring Security Web App添加项目依赖项

项目依赖关系在build.gradle文件中定义(请参见下文)。 这个文件中有很多事情要做,本教程不会尝试向您解释Gradle构建系统。 随时检查他们的文档 。 我只想指出几件事。

首先,请注意,我们包括了okta-spring-boot-starter 。 该项目大大简化了Okta与Spring Boot应用程序的集成。 如果没有此启动程序,完全可以使用Okta和Spring Boot。 实际上,直到引入“组”和“角色”为止,两者之间的差异很小(主要涉及application.yml更改)。 但是,一旦开始尝试集成组和角色,Okta Spring Boot Starter会节省大量代码。 如果您想更深入一点,请看一下Okta Spring Boot Starter GitHub项目 。

其余的依赖关系涉及Spring和Spring Boot。 您会注意到org.springframework.boot依赖项都没有版本号。 这是因为Spring io.spring.dependency-management Gradle插件完成了一些幕后魔术。 Spring Boot版本由build.gradle文件顶部附近的构建脚本属性springBootVersion设置。 基于此版本号,Spring依赖性管理插件决定要包括的依赖性版本。

我们还引入了org.springframework.boot Gradle插件,该插件添加了我们将用于运行应用程序的bootRun任务。

  • spring-boot-starter-securityspring-boot-starter-web是Spring Boot的核心依赖项。
  • 必须使用spring-security-oauth2-autoconfigure才能使用@EnableOAuth2Sso批注,该批注用于将OAuth和Single Sign-On挂接到我们的应用程序中。
  • spring-boot-starter-thymeleafthymeleaf-extras-springsecurity4引入了Thymeleaf模板系统,并将其与Spring Security集成。
buildscript {  ext {  springBootVersion = '2.0.5.RELEASE'  }  repositories {  mavenCentral()  }  dependencies {  classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")  }
}  apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'  group = 'com.okta.springboot'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8  repositories {  mavenCentral()
}  dependencies {  compile('com.okta.spring:okta-spring-boot-starter:0.6.0')  compile('org.springframework.boot:spring-boot-starter-security')  compile('org.springframework.boot:spring-boot-starter-web')  compile('org.springframework.boot:spring-boot-starter-thymeleaf')  compile('org.thymeleaf.extras:thymeleaf-extras-springsecurity4')  compile('org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.0.5.RELEASE')  testCompile('org.springframework.boot:spring-boot-starter-test')  "testCompile('org.springframework.security:spring-security-test')
}  /*  This is required to resolve a logging dependency conflict between the okta-spring-boot-starter and the various spring dependencies. */
configurations.all {  exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'  exclude group: 'org.springframework.boot', module: 'logback-classic'
}

了解您的Spring Boot应用程序

Java Web应用程序只有三个类文件和几个模板。 显然,Spring Boot在后台进行了大量繁重的工作,但是我们的类文件中发生了什么?

应用程序入口点在SpringSimpleApplication类中:

@SpringBootApplication
public class SpringSimpleApplication {  public static void main(String[] args) {  SpringApplication.run(SpringSimpleApplication.class, args);  }
}

这里发生了两个重要的事情,这些事情使事情发生了变化:1)我们使用@SpringBootApplication批注,以及2)我们的main方法调用SpringApplication.run()方法。 这是整个Spring / Spring Boot系统的入口。

SpringSecurityWebAppConfig类是一种使用Java代码配置Spring Boot处理Web应用程序安全性的方式。 在这里,我们使用HttpSecurity对象从所有端点中删除授权。 默认情况下,Spring Boot的行为是相反的:所有端点都需要授权。

@Configuration
public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter {  @Override  protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().permitAll();          }
}

@Configuration注释告诉Spring我们正在使用该类作为编程配置的源,从而允许我们重写configure()方法。

最后一个Java类SimpleAppController是我们唯一的控制器对象。 Spring Boot Web应用程序中的控制器是URL请求映射到Java代码的地方。 @Controller注释告诉Spring此类是一个控制器。

@Controller
class SimpleAppController {  @RequestMapping("/")  String home() {  return "home";  }  @RequestMapping("/restricted")  String restricted() {  return "restricted";  }  }

使用@RequestMapping批注在类方法和URL之间建立连接。

我们有两个映射:

  1. “家庭”映射
  2. “受限”映射

请记住,一开始实际上没有任何“限制”,所以不要为此感到困惑。 您将锁定该映射一点。

还要注意,这些类返回一个简单的文本字符串,但这会自动变成完整的html文件。 这是build.gradle文件中包含的Thymeleaf依赖项的一部分。 这些字符串被假定为模板文件名,默认情况下是类路径上templates目录中的路径。

因此,“ home”被映射到src/main/resources/templates/home.html模板文件。 当将Web应用程序打包到最终的jar中时,会将整个资源文件夹复制到类路径中,以便可以在运行时访问templates目录。

为OAuth 2.0单一登录设置Okta

现在,您将为我们的应用设置授权。 Okta使这个超级容易。 您应该已经注册了一个免费的developer.okta.com帐户。 现在,您将创建一个OpenID Connect(OIDC)应用程序,以与OAuth 2.0单一登录(SSO)一起使用。

如果您还不熟悉它们的话,可能会有很多术语和缩写。 很简单, OAuth 2.0是授权的行业标准-一种标准化且经过测试的方法,授权服务器和应用程序可以通过该方法进行通信以促进用户授权。 OpenID Connect是OAuth 2.0之上的一层,用于标准化和简化授权过程以及提供用户验证。 它们一起为应用程序与提供身份验证和授权服务的远程服务器(例如Okta)进行交互提供了一种行之有效的方法。

要创建OIDC应用,请打开Okta开发人员信息中心。 单击“ 应用程序”顶部菜单项,然后单击“ 添加应用程序”

您应该看到以下屏幕。 单击“ Web”选项的图标。 单击下一步


您需要更新一些初始配置选项。 首先将名称更改为更具描述性的名称。 我使用了“ Okta Spring Boot简单Web应用程序”。 接下来,将登录重定向URI更新为http://localhost:8080/login 。 单击完成


这将带您进入新应用程序的常规配置选项卡。 向下滚动并记下客户端ID和客户端密码。 稍后您将需要这些。


这就是为Okat设置Okta所需要做的一切! 现在,让我们返回Spring Boot应用程序,并将新的OIDC应用程序挂接到Spring Boot应用程序中。

为单点登录(SSO)配置Spring Boot应用

现在,您需要配置Spring Boot应用程序以与Okta服务器进行交互。 这非常容易。 我们需要做两件事:

  1. 添加@EnableOAuth2Sso批注
  2. 更新application.yml配置

首先将@EnableOAuth2Sso批注添加到SpringSecurityWebAppConfig类。

@EnableOAuth2Sso
@Configuration
public class WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {  @Override  protected void configure(HttpSecurity http) throws Exception {  http.authorizeRequests().anyRequest().permitAll();          }
}

@EnableOAuth2Sso批注会做很多事情。 值得深入了解正在发生的事情。 您可以查看有关注解本身的Spring文档 ,以及它们的Spring Boot和OAuth2教程 。

我想指出的一件事(公元前这使我烦恼了一阵子,而我只是想出了这一点)是,您可以将此注释放在项目中的其他类上。 但是,如果这样做,请注意Spring将创建一个WebSecurityConfigurerAdapter并将其添加到安全链中。 由于我们还将创建一个WebSecurityConfigurerAdapter,因此将有两个,并且您将收到有关链订单冲突的错误。 这是因为两个WebSecurityConfigurerAdapters在默认情况下将使用相同的链顺序。 您可以通过在自定义类中添加@Order(101)批注来解决此错误。 但是,更好的方法是将@EnableOAuth2Sso批注添加到我们的WebSecurityConfigurerAdapter类WebSecurityConfigurerAdapter ,Spring将使用该类而不是创建重复的类。

您需要进行的第二个更改是更新src/main/resources/application.yml文件,为来自Okta OIDC应用程序的OAuth SSO值填写一些Okta特定的配置选项。

您需要从上面创建的应用程序中填写您的客户ID和客户机密。 您还需要更改发行者URL,以使其反映您的Okta预览URL,例如dev-123456.oktapreview.com

server:  port: 8080  spring:  resources: static-locations: "classpath:/static/"  okta:  oauth2: issuer: https://{yourOktaDomain}/oauth2/default  clientId: {yourClientId}  clientSecret: {yourClientSecret}rolesClaim: groups

完善我们的权限

现在,您将要更新SpringSecurityWebAppConfig类,以便拥有一个公共主页和一个受限制的“受限制”页面。 我们通过对HttpSecurity对象使用Spring的流畅API来实现此目的。

import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;@EnableOAuth2Sso
@Configuration
public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter {  @Override  protected void configure(HttpSecurity http) throws Exception {  http.authorizeRequests()  .antMatchers("/").permitAll() // allow all at home page.antMatchers("/img/**").permitAll()  // allow all to access static images.anyRequest().authenticated();  // authenticate everything else!}
}

重新启动您的应用程序,现在您应该能够:

  1. 无需认证即可查看主页
  2. 未经身份验证就无法看到/restricted页面
  3. 能够使用Okta单一登录进行身份验证

本教程中的这一点与GitHub存储库中的OktaOAuthSSO标签相对应。

看看Thymeleaf模板

总体而言,Thymeleaf模板是很容易解释的,但是我确实想指出几件事。 Thymeleaf模板是完全有效HTML5,这很好。 如果您想深入了解,可以访问他们的网站和他们的文档 。

我想指出的是模板如何引入身份验证信息。 为此,我们使用了thymeleaf-extras-springsecurity插件。 这是包含在build.gradle文件中的以下行:

compile ("org.thymeleaf.extras:thymeleaf-extras-springsecurity4")

并且作为主<html>标记上的XML名称空间属性包含在模板文件中。

xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"

这个插件使我们可以检查是否使用带有自定义SPEL表达式(Spring表达式语言)的th:if属性对用户进行了身份验证。 它还允许我们插入身份验证属性。 在下面,您将看到一个跨度<span th:text="${#authentication.name}"></span> ,该<span th:text="${#authentication.name}"></span>用于插入已验证用户的名称。

<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>  <!--/*/ <th:block th:include="fragments/head :: head"/> /*/-->
</head>
<body>
<div class="container-fluid">  <div class="row">  <div class="box col-md-6 col-md-offset-3">  <div class="okta-header">  <img src="img/logo.png"/>  </div>  <!--/* displayed if account IS NOT null, indicating that the user IS logged in */-->  <div th:if="${#authorization.expression('isAuthenticated()')}">  <h1 th:inline="text">Hello, <span th:text="${#authentication.name}"></span>!</h1>  <a href="/restricted" class="btn btn-primary">Restricted</a>  </div>  <!--/* displayed if account IS null, indicating that the user IS NOT logged in */-->  <div th:unless="${#authorization.expression('isAuthenticated()')}">  <h1>Who are you?</h1>  <a href="/restricted" class="btn btn-primary">Restricted</a>  </div>  </div>  </div>
</div>
</body>
</html>

thymeleaf-extras-springsecurity插件还具有其他一些不错的功能。 如果您想更深入一点,请查看GitHub上的项目存储库 。

通过组成员身份安全访问

本教程的下一步是使用将在Okta上创建和定义的用户组添加基于组的身份验证。 一个非常常见的示例是让网站的“管理”部分和网站的“用户”部分,以及可能向所有人开放的公共主页。 在此示例中,“管理员”和“用户”将对应于两个不同的组,其中经过身份验证的用户可以是其成员。 我们要做的是能够基于用户组成员身份限制对URL端点的访问,并能够将用户分配给这些组。

旁注:小组与角色。 有什么不同?

  • “组”是用户的集合,并且权限已分配给该组。 一般来说,至少在整个会话期间,组成员资格是相对静态的。
  • “角色”是用户在该角色下执行操作时可以继承的一组权限。 角色本质上通常更具动态性。 用户可以具有许多角色。 经常根据复杂的标准激活或停用角色,并且在整个用户会话中经常可能会更改角色。

实际上,对于简单的授权系统,它们非常相似。 主要区别在于,组基于个人身份进行分类,而角色则基于允许的活动进行分类。 您可能会在狂野的互联网上看到无视这种差异的应用程序和教程,因为它们在功能上有些微妙。 (但是现在您知道了。您可以进入所涉及的教程的评论主题,并撰写评论以纠正作者。)

在Okta中配置授权组

转到您的developer.okta.com仪表板。 从顶部菜单中,转到“ 用户” ,然后单击“ 组”


单击添加组按钮。

将组命名为“ Admin”并对其进行描述(我放了“ Administrators”,无论您在这里实际输入什么,都无所谓,只是描述性的)。

单击组名称以打开组,然后单击添加成员按钮。 将您的用户添加到Admin组。

接下来,添加一个不是管理员的新用户。

  • 从顶部菜单转到“ 用户 ”,然后单击“ 人员”
  • 单击添加人
  • 填写弹出表单:
    • 名:不

接下来您需要做的是向默认授权服务器添加一个“组”声明。

  • 从顶部菜单转到API ,然后单击“ 授权服务器
  • 单击默认授权服务器。
  • 单击“ 索赔”选项卡。
  • 点击添加声明按钮。
  • 更新弹出表单以匹配下面的图像
    • 名称:团体

您在这里所做的就是告诉Okta在发送给您的应用程序的访问令牌中包含“组”声明。 这是Okta的OAuth方法,用于向您的应用程序告知您已通过身份验证的用户所属的组。 令人困惑的是,这些在Spring应用程序端被称为“权威”,这是OAuth服务器与应用程序通信的组/角色/特权的抽象术语。

现在我们有两个用户。 您的主要用户(已添加到Admin组中)和一个新用户(不在admin组中)。 我们还配置了Okta,将群组声明添加到访问令牌中。 现在,我们要做的就是对应用程序代码进行一些更改!

更新您的Spring Boot + Spring Security App以使用基于组的授权

Okta Spring Boot Starter真正开始发挥作用。 通常,如果您想将我们发送令牌的安全组和组声明映射到应用程序中的组,则必须编写一两个提取程序类来处理提取操作,也许还要编写一个组类。 Okta Spring Boot Starter可以为您完成所有这些工作!

您要做的第一件事是在SpringSecurityWebAppConfig类中添加以下注释。

@EnableGlobalMethodSecurity(prePostEnabled = true)

像这样:

import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;@EnableOAuth2Sso
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter {  /* class contents omitted for brevity */
}

此注释启用了我们将要使用的下一个注释@PreAuthorize注释。 该注释使我们可以使用Spring Expression Language(SpEL)谓词来确定控制器方法是否得到授权。 谓词表达式会在应用程序甚至进入控制器方法之前执行(因此需要“预先”授权)。

SimpleAppController类中,添加一个名为admin的新方法,如下所示:

import org.springframework.security.access.prepost.PreAuthorize;@Controller
class SimpleAppController {  /* other controllers omitted for clarity */ @RequestMapping("/admin")  @PreAuthorize("hasAuthority('Admin')")  String admin() {  return "admin";  }  }

概括一下,此方法执行以下操作:

  • /admin url端点创建一个映射;
  • /admin端点分配基于SpEL的授权方案;
  • 并简单地返回Thymeleaf模板的名称,假设该/templates位于/templates目录中(我们将在下一个目录中创建)。

创建新的管理模板页面。 在src/main/resources/templates目录中,创建一个名为admin.html的新文件,其内容如下:

<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>  <!--/*/ <th:block th:include="fragments/head :: head"/> /*/-->
</head>
<body>
<div class="container-fluid">  <div class="row">  <div class="box col-md-6 col-md-offset-3">  <div class="okta-header">  <img src="img/logo.png"/>  </div>  <h1>Welcome to the admin page!</h1>  <a href="/" class="btn btn-primary">Go Home</a>  </div>  </div>
</div>
</body>
</html>

您可能会问自己@PreAuthorize批注中使用的SpEL表达式是什么意思。 为什么SpEL表达式具有hasAuthority而不具有hasGroup ? 正确的答案有些复杂,这与Spring在不同上下文中调用权限特权和权限有关,可以在应用程序中将其映射到组和角色。 当使用Spring Boot和OAuth时,“权限”通常等同于“角色”,这很好。 但是您说我们使用的是群组,而不是角色? 对。 实际上,在这种情况下,这没关系,因为Okta知道我们在谈论群组,而应用程序知道我们在谈论群组,并且在中间,我们仅使用group声明和Authority字段来传达文本代表用户所属组的字符串。

有用的提示:

如果要检查Spring Boot App正在接收的身份验证信息,可以在return语句之前的控制器方法之一中添加以下行。

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

确实在此行上或其后设置一个断点,然后使用允许您检查身份验证对象的调试器运行该应用程序。 这是学习和调试问题的好方法。

试用您的新Spring Boot + Spring Security Web App!

就是这样。 您应该能够重新启动应用程序并以两个不同的用户身份登录。 只有添加到“管理员”组的用户才能访问“管理员”页面。 您必须直接导航到http:// localhost:8080 / admin(因为我们没有添加链接或按钮)。 如果您尝试与其他用户一起导航到管理页面,则会看到漂亮的whitelabel错误页面,其中显示403 /未经授权的错误。

请记住,在用户之间切换时,您必须停止应用程序,注销您的developer.okta.com帐户,然后重新启动应用程序。 您也可以在浏览器中使用隐身窗口。

本教程的这一部分与GroupsAuth标记相对应,您可以使用以下命令git checkout tags/GroupsAuth

了解有关Spring Boot,Spring Security和安全用户管理的更多信息

您在这里取得了一些实际进展。 您了解了如何创建一个简单的Spring Boot应用程序以及如何使用Thymeleaf模板。 您已经了解到Okta使OAuth 2.0 Single Sign-On集成到您的应用中有多么容易。 您已经了解了如何使用WebSecurityConfigurerAdapter子类和http.authorizeRequests() API来限制对控制器端点的访问。

最后,您已经了解了如何在Okta上创建组和用户,如何将它们绑定到Spring Boot应用程序中,以及如何使用@PreAuthorize批注根据组成员身份配置授权。

如果您想查看这个完整的项目,可以在Github上找到该仓库: https : //github.com/moksamedia/okta-spring-simple-app 。

如果您想了解有关Spring Boot,Spring Security或Okta的更多信息,请查看以下任何出色的教程:

  • Spring Boot,OAuth 2.0和Okta入门
  • 15分钟内将单一登录添加到您的Spring Boot Web App
  • 使用多重身份验证保护您的Spring Boot应用程序安全
  • 使用Spring Boot和GraphQL构建安全的API

如果您想深入研究,请查看Okta Spring Boot Starter GitHub页面 。

如果您对此帖子有任何疑问,请在下面添加评论。 有关更多精彩内容, 请在Twitter上关注@oktadev , 在Facebook上关注我们,或订阅我们的YouTube频道 。

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。

“使用Spring Boot和Spring Security在15分钟内构建Web应用程序”最初于2018年9月26日在Okta开发人员博客上发布。

翻译自: https://www.javacodegeeks.com/2019/02/build-web-app-spring-boot-spring-security.html

在15分钟内使用Spring Boot和Spring Security构建一个Web应用程序相关推荐

  1. IDEA 2019 生成Spring Boot项目,编写第一个Hello World程序,并打包成jar

    IDEA集成了生成Spring Boot项目的功能,不需要你去 start.spring.io 上下载,使用方法如下: 新建项目,选择Spring Initializr: 然后点NEXT: 勾选需要的 ...

  2. 一个具有Spring Boot,Spring Security和Stormpath的简单Web应用程序-15分钟

    建筑物身份管理,包括身份验证和授权? 尝试Stormpath! 我们的REST API和强大的Java SDK支持可以消除您的安全风险,并且可以在几分钟内实现. 注册 ,再也不会建立auth了! 更新 ...

  3. 如何在开盘15分钟内发现当天黑马

    如何在开盘15分钟内发现当天黑马 在每日正式开市前,通过集合竟价开盘来浏览大盘和个股,这是一天中最宝贵的时间!也是捕捉当日黑马的最佳时刻! 因为通过观察大盘开盘的情况(是高开还是低开),能发现个股是怎 ...

  4. 服务器创建多个dhcp服务_如何在15分钟内创建无服务器服务

    服务器创建多个dhcp服务 by Charlee Li 通过李李 如何在15分钟内创建无服务器服务 (How to create a serverless service in 15 minutes) ...

  5. h5正则表达式_正则表达式需要5天才能运行。 因此,我构建了一个可以在15分钟内完成操作的工具。...

    h5正则表达式 by Vikash Singh 由Vikash Singh 正则表达式需要5天才能运行. 因此,我构建了一个可以在15分钟内完成操作的工具. (Regex was taking 5 d ...

  6. vr设备应用程序_在15分钟内构建一个VR Web应用程序

    vr设备应用程序 在15分钟内,您可以开发一个虚拟现实应用程序,并在Web浏览器,VR头盔或Google Daydream上运行它. 关键是A-Frame ,这是Mozilla VR Team构建的开 ...

  7. mvc移动创建oracle表,使用 ASP.NET MVC (C#)在15分钟内创建电影数据库应用程序 | Microsoft Docs...

    使用 ASP.NET MVC 在 15 分钟内创建电影数据库应用程序 (C#)Create a Movie Database Application in 15 Minutes with ASP.NE ...

  8. 开盘15分钟内扑捉当天黑马

    开盘15分钟内扑捉当天黑马               在9:30开市前, 通过集合竟价开盘时,我们都有几分钟的时间浏览大盘和个股, 这是一天中最宝贵的时间!是扑捉当日黑马的最佳时刻! 因为能看出大盘 ...

  9. 1000桶水,其中一桶有毒,猪喝毒水后会在15分钟内死去,想用一个小时找到这桶毒水,至少需要几头猪?具体该如何实现方法讲解

    对于此问题,一个思路是通过对问题分解: 首先一个猪在一个小时内的状态可以分为5种: 一.0分钟喝水,15分钟死去 二.15分钟活着再喝水,30分钟死去 三.30分钟活着再喝水,45分钟死去 四.45分 ...

最新文章

  1. 深度学习的发展方向: 深度强化学习!
  2. 后门BROOTKIT代码学习和原理分析
  3. linux debain systemd 开机启动 nodejs 兼容原initd启动 forever 开机自启
  4. solr6 mysql_solr6 从mysql上导入数据
  5. Python3之deepcopy在print调试中的使用技巧
  6. 【Linux】一步一步学Linux——ping命令(150)
  7. C#如何判断程序调用的exe已结束
  8. Leetcode | 107. Binary Tree Level Order Traversal II
  9. linux openoffice centos,centos8 openoffice安装
  10. NVelocity系列:NVelocity配置详解
  11. 罗永浩卖半价iPhone秒没,网友晒开挂软件,怪不得你抢不到
  12. 置顶,博客中所有源码 github
  13. Java自增原子性问题(测试Volatile、AtomicInteger)
  14. Spring Boot 系列(七)Swagger2-生成RESTful接口文档
  15. SSO —— 单点登录CAS与OAuth2
  16. project安装教程/包
  17. Python——QQ/微信 邮件 群发技术实现
  18. 一个学习式的mogoLink框架介绍
  19. [几何] BZOJ 2710 [Violet 1]追风者 POJ 3924 Tornado
  20. jquery实现图片上传预览

热门文章

  1. 传送门(最短路树+可并堆)
  2. codeforces gym-101745 C-Infinite Graph Game 分块
  3. 这些代码优化的方法,你都用过吗
  4. Java经典面试题一
  5. Java高级篇——深入浅出Java类加载机制
  6. Spring Boot中mapper包所放位置的配置
  7. 《白鹿原》金句摘抄(二)
  8. JavaScript实现四则运算
  9. 2014年JAVA省赛B组---第四题---大衍数列
  10. mysql根据注释搜索表