带有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来实现此目的,但是我发现它很难使用,并且在创建更复杂的文档时对我来说效果不佳。 因此,对于这个项目,经过一…

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

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

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

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

使用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上天新闻开始,以及近几年js语言在整个互联网的广泛应用,注定未来js语言有着不平凡的使命,跨端(一套代码多端运行)、易UI(前端开发UI的便利)、丰富的生态&#xf…

JAVA记录-Servlet介绍

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

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

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

OpenMap教程4 –图层

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

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

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

为什么写公众号,为什么改名字

这是一篇水果文,啥叫水果文?比水文稍微有点内容,我暂时这么解释吧。最近刚刚开始决定写公众号,其实这个订阅号申请的还蛮早的,当时是为了学习开发公众号而创建的,所以中间有过一段空档期(呸&…

chrome浏览器解决ajax跨域问题

方法一 1、右键谷歌快捷方式,选择“属性”。 2、打开属性窗口,切换到“快捷方式”选项卡。 3、在目标路径的后面添加【 --disable-web-security】,其中chrome.exe与--disable之间有一个空格 4、点击应用,然后点击确定关闭窗口。 5…

前端的使命来了

最近国家工信部发布了一则关于重大App进行适老化改造的政策目的在于随着互联网的普及,有一部分群体在互联网应用的使用上存在着一定的障碍,为了保证这部分人能够顺利的使用手机中的App,国家出手了!现在人们的生活越来越离不开互联…

第二章 Burp Suite代理和浏览器设置

Burp Suite代理工具是以拦截代理的方式,拦截所有通过代理的网络流量,如客户端的请求数据、服务器端的返回信息等。Burp Suite主要拦截http和https协议的流量,通过拦截,Burp Suite以中间人的方式,可以对客户端请求数据、…

Multiavatar头像生成,要多少有多少

还在为选一个个性十足,不同于别人的头像而烦恼吗?12,230,590,464个头像够你选择够不够?Multiavatar一款集多文化头像生成器,它可以根据不同的种族,不同的文化,不同的年龄,不同的世界观&#xff…

将Java 8流解析为SQL

当Java 8发行并且人们开始流式处理各种东西时,很快他们就开始想象如果可以以相同的方式使用数据库将有多大的潜力。 本质上,关系数据库由以表状结构组织的巨大数据块组成。 这些结构非常适合进行过滤和映射操作,如SQL语言的SELECT&#xff0c…

TCP Congestion Control

TCP Congestion Control Congestion occurs when total arrival rate from all packet flows exceeds R over a sustained(维持) period of timeBuffers(缓冲) at multiplexer will fill and packets will be lostPhases of Congestion Behavior Light traffic Arrival Rate &l…

SVG格式的Icon,用了你就知道有多香

继阿里的iconfont之后,字节跳动也出品了自己的矢量图标库,可以实现根据单一SVG源文件变换出多种主题, 具备丰富的分类、更轻量的代码和更灵活的使用场景。矢量SVG图标的出现,完全改变了前端的开发方式,之前总是通过设计…

sql server2016里面的json功能 - 转

测试一下基本的,从查询结果里面构造一个json 的格式 create table t1(ID int identity,name nvarchar(50),Chinese int ,Math int)insert into t1 values (张三,90,80),(李四,75,90),(王五,68,100) select * from t1select * from t1 for json auto--查询结果 ID …

CSS实现TikTok文字抖动效果

前端同学在日常开发中精彩会因为一些动效和设计争的面红耳赤,设计希望用代码实现,前端要设计出gif图,最后谁也不让谁,设计走了,留下了前端独自加班......CSS技术是前端必须掌握的一项技能,不仅要掌握&#…