带有JWT示例的​​Spring Oauth2

有时以前,我们发表了一篇文章,分享了一种在云环境中实现无状态会话的自定义方法。 今天,让我们探讨为Spring Boot应用程序设置Oauth2身份验证的另一个流行用例。 在此示例中,我们将使用JSON Web令牌(JWT)作为Oauth2令牌的格式。

该示例部分是基于Spring Security Oauth 2的官方示例开发的。但是,我们将专注于理解Oauth 2请求的原理。

源代码位于https://github.com/tuanngda/spring-boot-oauth2-demo.git

背景

Oauth2和JWT

当您要使用Oauth2和JWT时,我们将不做详细介绍。 通常,如果需要允许其他人为您的服务构建前端应用程序,则可能需要采用Oauth。 我们专注于Oauth2和JWT,因为它们是市场上最流行的身份验证框架和协议。

Spring安全Oauth 2

Spring Security Oauth2是Oauth 2的实现,它是在Spring Security之上构建的,Spring Security是一个非常可扩展的身份验证框架。

总体而言,Spring Security包括2个基本步骤:为每个请求创建一个身份验证对象,并根据身份验证应用授权检查。 第一步是在多层安全筛选器中完成的。 根据配置,每一层都可以帮助创建基本身份验证,摘要身份验证,表单身份验证或我们选择自行实现的任何自定义身份验证的身份验证。 我们在上一篇文章中构建的客户端会话是一种自定义身份验证,而Spring Security Oauth 2是另一种自定义身份验证。

因为在此示例中,我们的应用程序既提供令牌又使用令牌,因此Spring Security Oauth 2不应是应用程序的唯一身份验证层。 我们需要另一种身份验证机制来保护令牌提供者端点。

对于集群环境,令牌或签名令牌的秘密(对于JWT)假定是持久的,但是我们跳过此步骤以简化示例。 同样,用户身份验证和客户端身份都是硬编码的。

系统设计

总览

在我们的应用程序中,我们需要设置3个组件

  • 授权端点和令牌端点,以帮助提供Oauth 2令牌。
  • WebSecurityConfigurerAdapter,这是一个身份验证层,其硬编码顺序为3(根据Dave Syer )。 该身份验证层将为包含Oauth 2令牌的任何请求设置身份验证和委托人。
  • 如果令牌丢失,则另一种身份验证机制可以保护令牌端点和其他资源。 在此示例中,我们选择基本身份验证是为了简化编写测试时的操作。 由于我们未指定顺序,因此它将采用默认值100。对于Spring安全性,顺序越低,优先级越高; 因此,我们应该期望Oauth 2在FilterChainProxy中进行基本身份验证之前。 在IDE中检查证明我们的设置正确。

过滤链

在上图中,Oauth2AuthenticationProcessingFilter出现在BasicAuthenticationFilter的前面。

授权服务器配置

这是我们的授权和令牌端点配置

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {@Value("${resource.id:spring-boot-application}")private String resourceId;@Value("${access_token.validity_period:3600}")int accessTokenValiditySeconds = 3600;@Autowiredprivate AuthenticationManager authenticationManager;@Beanpublic JwtAccessTokenConverter accessTokenConverter() {return new JwtAccessTokenConverter();}@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(this.authenticationManager).accessTokenConverter(accessTokenConverter());}@Overridepublic void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {oauthServer.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')").checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')");}@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory().withClient("normal-app").authorizedGrantTypes("authorization_code", "implicit").authorities("ROLE_CLIENT").scopes("read", "write").resourceIds(resourceId).accessTokenValiditySeconds(accessTokenValiditySeconds).and().withClient("trusted-app").authorizedGrantTypes("client_credentials", "password").authorities("ROLE_TRUSTED_CLIENT").scopes("read", "write").resourceIds(resourceId).accessTokenValiditySeconds(accessTokenValiditySeconds).secret("secret");}
}

关于此实现,没有什么值得注意的事情。

  • 设置JWT令牌就像使用JwtAccessTokenConverter一样简单。 因为我们从未设置签名密钥,所以它是随机生成的。 如果我们打算将应用程序部署到云中,则必须在所有授权服务器之间同步签名密钥。
  • 除了选择创建身份验证管理器之外,我们还选择从Spring容器中注入现有的身份验证管理器。 通过此步骤,我们可以与基本身份验证过滤器共享身份验证管理器。
  • 可能有受信任的应用程序,而不是受信任的应用程序。 受信任的应用程序可以有自己的秘密。 这是客户凭证授权授予所必需的。 除客户端凭据外,所有其他三个授予都需要资源所有者的凭据。
  • 我们允许匿名检查令牌端点。 使用此配置,无需基本身份验证或Oauth 2令牌即可访问检查令牌。

资源服务器配置

这是我们的资源服务器配置配置

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {@Value("${resource.id:spring-boot-application}")private String resourceId;@Overridepublic void configure(ResourceServerSecurityConfigurer resources) {resources.resourceId(resourceId);}@Overridepublic void configure(HttpSecurity http) throws Exception {http.requestMatcher(new OAuthRequestedMatcher()).authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll().anyRequest().authenticated();}private static class OAuthRequestedMatcher implements RequestMatcher {public boolean matches(HttpServletRequest request) {String auth = request.getHeader("Authorization");// Determine if the client request contained an OAuth Authorizationboolean haveOauth2Token = (auth != null) && auth.startsWith("Bearer");boolean haveAccessToken = request.getParameter("access_token")!=null;return haveOauth2Token || haveAccessToken;}}}

这里有几件事要注意:

  • 添加了OAuthRequestedMatcher,以便Oauth过滤器仅处理Oauth2请求。 我们添加了此内容,以便在基本身份验证层而不是Oauth 2层将拒绝未授权的请求。 在功能方面,这可能没有任何区别,但出于可用性考虑,我们对其进行了添加。 对于客户端,他们将收到401 HTTP状态,其中包含此新标头和旧标头:
    • WWW-Authenticate:基本领域=“领域”
  • 使用新的响应标头,浏览器将自动提示用户输入用户名和密码。 如果您不希望任何其他身份验证机制访问该资源,则无需执行此步骤。
  • 某些浏览器(例如Chrome)喜欢在发出AJAX调用之前发送OPTIONS请求以查找CORS。 因此,最好始终允许OPTIONS请求。

基本身份验证安全配置

如前所述,因为我们需要保护令牌提供者端点。

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {@Autowiredpublic void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("user").password("password").roles("USER").and().withUser("admin").password("password").roles("USER", "ADMIN");}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll().anyRequest().authenticated().and().httpBasic().and().csrf().disable();}@Override@Beanpublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}
}

有几件事要注意:

  • 我们公开了AuthenticationManager bean,以便我们的两个身份验证安全适配器可以共享一个身份验证管理器。
  • Spring Security CSRF可与JSP无缝协作,但对RestAPI来说很麻烦。 因为我们希望将此示例应用程序用作用户开发自己的应用程序的基础,所以我们关闭了CSRF并添加了CORS过滤器,以便可以立即使用它。

测试中

我们严格按照Oauth2规范为每种授权授予类型编写了一个测试方案。 由于Spring Security Oauth 2是基于Spring Security框架的实现,因此我们的兴趣转向查看如何构造基础身份验证和主体。

在总结实验结果之前,让我们快速看一下要记录的内容。

  • 对令牌提供者端点的大多数请求都是使用POST请求发送的,但它们包含用户凭据作为参数。 即使为了方便起见,我们将此凭据作为url的一部分放置,也切勿在Oauth 2客户端中执行此操作。
  • 我们创建了两个端点/ resources / principal/ resources / roles来捕获Oauth 2身份验证的主体和权限。

这是我们的设置:

用户 类型 当局 凭据
用户 资源所有者 ROLE_USER ÿ
管理员 资源所有者 ROLE_ADMIN ÿ
普通应用 客户 ROLE_CLIENT ñ
受信任的应用 客户 ROLE_TRUSTED_CLIENT ÿ

赠款类型 用户 客户 主要 当局
授权码 用户 普通应用 用户 ROLE_USER
客户凭证 不适用 受信任的应用 受信任的应用 没有权限
隐含的 用户 普通应用 用户 ROLE_USER
资源所有者密码凭证 用户 受信任的应用 用户 ROLE_USER

除客户端凭据外,此结果与预期的相当。 有趣的是,即使客户端通过客户端证书检索Oauth 2令牌,批准的请求仍然没有任何客户端权限,而仅具有客户端证书。 我认为这是有道理的,因为隐式授予类型的令牌无法重用。 这是我们发现的

翻译自: https://www.javacodegeeks.com/2016/04/spring-oauth2-jwt-sample.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/354718.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring源码解析-实例化bean对象

spring加载配置文件,AbstractApplicationContext类中的refresh方法起着重要的作用。 Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.准备刷新…

java docx文档解析_带有docx4j的Java Word(.docx)文档

java docx文档解析几个月前,我需要创建一个包含许多表和段落的动态Word文档。 过去,我曾使用POI来实现此目的,但是我发现它很难使用,并且在创建更复杂的文档时对我来说效果不佳。 因此,对于这个项目,经过一…

Win8.1部署 .NET Framework 3.5 安装方式

Windows 8.1中包含.NET Framework,操作系统安装过程中默认安装 .NET Framework 4.5.1。如果程序需要.NET Framework 3.5支持,将自动启用相关功能。 注意: 1. .NET Framework 3.5同时支持基于 .NET Framework 2.0/3.0/3.5构建应用程序。 2. 在…

@Autowired所有的东西!

最近,我写了Autowired注释 ,它使我们可以编写更少的代码,从而使我们的生活更轻松 。 但是,使用它通常会使您的设计更加复杂。 尤其是当我们谈论在类的属性上使用它时。 它更容易违反 单一责任原则 。 这样可以更容易地注意到这一…

Python基础-闭包

闭包:闭包内部函数定义函数时的环境 def outer():x 10def inner(): # 条件一 inner就是内部函数print(x) # 条件二 外部环境的一个变量return inner # 结论 内部函数inner就是一个闭包 outer()() 转载于:https://www.cnblogs.com/fansik/p/7676231.html

jit即时编译_热点中的即时编译器(JIT)

jit即时编译即时编译器(JIT)的概念以及更广泛的自适应优化是除Java(.Net,Lua,JRuby)之外的许多语言中众所周知的概念。 为了解释什么是JIT编译器,我想先定义一个编译器概念。 根据维基百科&…

每天十分钟系列:JS数据操作之神奇的map()

Array.prototype.map() map()方法可以创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。 demo1 上面的例子,在控制台中打印的结果是: 1 2 3 4 5 demo2 javascript学习交流群:453833554 上面的例子…

JSON格式数据与数据组件

1.将JSON格式数据转化为wex5data数据组件中的数据,且数据列数不必一 一对应,但转化的列数据的列名与数据表字段相同。 Model.prototype.goodsDataCustomRefresh function(event){var url require.toUrl("./json/goodsData.json");$.ajaxSett…

作业十三

<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>GZCC</title> </head> <body> <h1>MIS问答平台</h1> <h2 id"2015">2015</h2> <div id&quo…

openshift_通过OpenShift超越云炒作

openshift您是否厌倦了为应用程序请求新的开发机器&#xff1f; 您是否为必须为应用程序设置新的测试环境感到烦恼&#xff1f; 您是否只想专注于和平开发应用程序而不会一直“沉迷于堆栈”&#xff1f; 我们听到你的声音。 我们也去过那里。 不用担心&#xff0c;OpenShift就在…

初级程序员需要接触好的架构代码

最近感触最深的就是一个项目需要好的架构设计&#xff0c;不会因为后面不断延伸业务需求造成业务代码的不断堆砌&#xff0c;破坏整个项目的层次结构&#xff0c;也让新来的团队成员更好的上手项目&#xff0c;从清晰的结构就能很快的了解整个业务的流程。一个好的架构设计&…

行动中的反思实践

在上一篇文章中 &#xff0c;我解释了最基本的敏捷实践是反思。 在本文中&#xff0c;我概述了组织&#xff0c;团队和人员如何在行动中运用反思的示例。 通过回顾反思 回顾是强大的工具&#xff0c;整个团队都可以使用它们来反思其当前的工作实践&#xff0c;以了解他们为持续…

python基本语法1.2--数的移位及与或抑或相关计算

#便于中文的显示# -*- coding: utf-8 -*- #指数表示 # a ** b <> power(a, b) print(10 ** 2) #100 print(10 ** 2.5) #316.22776601683796 #做除法 # //: 返回商的整数部分 print(23 // 5) #4 print(28.7 // 4.4) #6.0#<<向左移位做乘法#>>向右移位做除法 …

fabric canvas 清空并重置画布

fabric.js是一个强大而简约的依赖HTML5上的 canvas的javascript库&#xff0c;Fabric在canvas元素顶部提供了交互式对象模型&#xff0c;它还具有SVG到画布&#xff08;和画布到SVG&#xff09;解析器&#xff0c;官网上提供了丰富的案例&#xff0c;可照葫芦画瓢&#xff0c;足…

使用vue-axios请求geoJson数据报错的问题

最近的项目用到了echarts一个带有散点地图的图表,按照正常jquery写法应该使用ajax请求geojson的数据动态去切换地图,就像下面这样 $.get(Js/map/ cityData.name .json, function(geoJson) {map(gr-map, cityData, geoJson, geoCoordMap);//调用地图方法}); 页面显示(成功) bu…

前端工业物联网开发(Electron + Typescript + Vue)

从SpaceX公司的带来的Javascript上天新闻开始&#xff0c;以及近几年js语言在整个互联网的广泛应用&#xff0c;注定未来js语言有着不平凡的使命&#xff0c;跨端&#xff08;一套代码多端运行&#xff09;、易UI&#xff08;前端开发UI的便利&#xff09;、丰富的生态&#xf…

JAVA记录-Servlet介绍

1.什么是Servlet Servlet是sun公司提供的一门用于开发动态web资源的技术。Sun公司在其API中提供了一个servlet接口&#xff0c;用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据)&#xff0c;需要完成以下2个步骤&#xff1a;1、编写一个Java类&#xff0c;实现…

前端jenkins打包编译发布项目流程

如今的前端项目已不像之前直接写完代码&#xff0c;扔到服务器直接运行了。免不了安装依赖&#xff0c;执行build过程&#xff0c;然后再将打包后的代码上传到服务器&#xff0c;可能还需要更改配置文件啥的。如此多的步骤严重影响开发的日常划水时间。所以jenkins自动化部署少…

OpenMap教程4 –图层

1.简介 在第一个教程中&#xff0c;我们创建了一个基本的OpenMap GIS应用程序&#xff0c;该应用程序在JFrame中显示一个从文件系统加载的具有一个形状图层的地图。 该教程基于com.bbn.openmap.app.example.SimpleMap 。 在第二篇教程中&#xff0c;我们扩展了基本应用程序以使…

Vue.js实战之Vuex的入门教程

在 Vue.js 的项目中&#xff0c;如果项目结构简单&#xff0c; 父子组件之间的数据传递可以使用 props 或者 $emit 等方式。 但是如果是大型项目&#xff0c;很多时候都需要在子组件之间传递数据&#xff0c;使用之前的方式就不太方便。Vue 的状态管理工具 Vuex 完美的解决了这…