In the past month, I had a chance to implement JWT auth for a side project. I have previously worked with JWT in Ruby on Rails, but this was my first time in Spring.

在过去的一个月中,我有机会为辅助项目实现JWT auth。 我以前曾在Ruby on Rails中使用JWT,但这是我第一次在Spring。

In this post, I will try to explain what I have learned and applied in my project to share my experience and hopefully help some people.

在这篇文章中,我将尝试解释我在项目中学到的知识和应用的知识,以分享我的经验,并希望能对一些人有所帮助。

We will start by taking a quick look at the theory behind JWT and how it works. Then we will look at how to implement it in a Spring Boot application.

我们将快速浏览一下JWT背后的理论及其工作原理。 然后,我们将研究如何在Spring Boot应用程序中实现它。

JWT基础 (JWT Basics)

JWT, or JSON Web Tokens (RFC 7519), is a standard that is mostly used for securing REST APIs. Despite being a relatively new technology, it is gaining rapid popularity.

JWT或JSON Web令牌( RFC 7519 )是一种标准,主要用于保护REST API。 尽管是相对较新的技术,但它正在Swift普及。

In the JWT auth process, the front end (client) firstly sends some credentials to authenticate itself (username and password in our case, since we're working on a web application).

在JWT身份验证过程中,前端(客户端)首先发送一些凭据以对其自身进行身份验证(在本例中为用户名和密码,因为我们正在处理Web应用程序)。

The server (the Spring app in our case) then checks those credentials, and if they are valid, it generates a JWT and returns it.

然后,服务器(在我们的示例中为Spring应用程序)检查这些凭据,如果它们有效,它将生成一个JWT并将其返回。

After this step client has to provide this token in the request’s Authorization header in the “Bearer TOKEN” form. The back end will check the validity of this token and authorize or reject requests. The token may also store user roles and authorize the requests based on the given authorities.

此步骤之后,客户端必须以“ Bearer TOKEN”形式在请求的Authorization标头中提供此令牌。 后端将检查此令牌的有效性并授权或拒绝请求。 令牌还可以存储用户角色并根据给定的权限授权请求。

实作 (Implementation)

Now let’s see how we can implement the JWT login and save mechanism in a real Spring application.

现在,让我们看看如何在真正的Spring应用程序中实现JWT登录和保存机制。

依存关系 (Dependencies)

You can see the list of Maven dependencies that our example code uses below. Note that the core dependencies like Spring Boot and Hibernate are not included in this screenshot.

您可以在下面查看我们的示例代码使用的Maven依赖项列表。 请注意,此屏幕快照中未包括诸如Spring Boot和Hibernate之类的核心依赖项。

保存用户 (Saving Users)

We will start by creating controllers to save users securely and authenticate them based on username and password.

我们将首先创建控制器以安全地保存用户并根据用户名和密码对他们进行身份验证。

We have a model entity called User. It is a simple entity class that maps to the USER table. You can use whatever properties you need depending on your application.

我们有一个称为用户的模型实体。 这是一个映射到USER表的简单实体类。 您可以根据应用程序使用所需的任何属性。

We also have a simple UserRepository class to save users. We need to override the findByUsername method since we will use it in authentication.

我们还有一个简单的UserRepository类来保存用户。 我们需要重写findByUsername方法,因为我们将在身份验证中使用它。

public interface UserRepository extends JpaRepository<User, String>{     User findByUsername(String username); }

We should never store plaintext passwords in the database because many users tend to use the same password for multiple sites.

我们绝不应该在数据库中存储纯文本密码,因为许多用户倾向于对多个站点使用相同的密码。

There are many different hashing algorithms, but the most commonly used one is BCrypt and it is a recommended method of secure hashing. You can check out this article for more information on the topic.

哈希算法有许多种,但是最常用的算法是BCrypt ,它是推荐的安全哈希方法。 你可以看看这个文章的主题的更多信息。

@Bean public BCryptPasswordEncoder bCryptPasswordEncoder() {    return new BCryptPasswordEncoder(); }

To hash the password, we will define a BCrypt bean in @SpringBootApplication and annotate the main class as follows:

为了哈希密码,我们将在@SpringBootApplication中定义一个BCrypt bean并注释主类,如下所示:

We will call the methods on this bean when we need to hash a password.

需要哈希密码时,将在此bean上调用方法。

We also need a UserController to save users. We create the controller, annotate it with @RestController, and define the corresponding mapping.

我们还需要一个UserController来保存用户。 我们创建控制器,使用@RestController对其进行注释,然后定义相应的映射。

In our application, we save the user based on a DTO object that is passed from the front end. You can also pass a User object in @RequestBody.

在我们的应用程序中,我们基于从前端传递的DTO对象保存用户。 您还可以在@RequestBody中传递一个User对象。

After we pass the DTO object, we encrypt the password field using the BCrypt bean we created earlier. You could also do this in the controller, but it is a better practice to put this logic in the service class.

传递DTO对象之后,我们使用之前创建的BCrypt bean加密密码字段。 您也可以在控制器中执行此操作,但是最好将此逻辑放在服务类中。

@Transactional(rollbackFor = Exception.class)
public String saveDto(UserDto userDto) {            userDto.setPassword(bCryptPasswordEncoder.encode(userDto.getPassword()));return save(new User(userDto)).getId();
}

认证过滤器 (Authentication Filter)

We need authentication to make sure that the user is really who they claim to be. We will be using the classic username/password pair to accomplish this.

我们需要身份验证以确保用户确实是他们声称的真实身份。 我们将使用经典的用户名/密码对完成此操作。

Here are the steps to implement authentication:

以下是实现身份验证的步骤:

  1. Create our Authentication Filter that extends UsernamePasswordAuthenticationFilter

    创建扩展UsernamePasswordAuthenticationFilter的身份验证过滤器

  2. Create a security configuration class that extends WebSecurityConfigurerAdapter and apply the filter

    创建扩展WebSecurityConfigurerAdapter的安全配置类并应用过滤器

Here is the code for our Authentication Filter – as you might know, filters are the backbone of Spring Security.

这是我们的身份验证过滤器的代码–您可能知道,过滤器是Spring Security的基础。

Let’s go over this code step by step.

让我们逐步看一下这段代码。

This class extends UsernamePasswordAuthenticationFilter which is the default class for password authentication in Spring Security. We extend it to define our custom authentication logic.

此类扩展了UsernamePasswordAuthenticationFilter ,后者是Spring Security中用于密码认证的默认类。 我们对其进行扩展以定义我们的自定义身份验证逻辑。

We make a call to the setFilterProcessesUrl method in our constructor. This method sets the default login URL to the provided parameter.

我们在构造函数中调用setFilterProcessesUrl方法。 此方法将默认登录URL设置为提供的参数。

If you remove this line, Spring Security creates the “/login” endpoint by default. It defines the login endpoint for us, which is why we will not define a login endpoint in our controller explicitly.

如果删除此行,Spring Security默认会创建“ / login”端点。 它为我们定义了登录端点,这就是为什么我们不会在控制器中显式定义登录端点的原因。

After this line our login endpoint will be /api/services/controller/user/login. You can use this function to stay consistent with your endpoints.

在此行之后,我们的登录端点将是/ api / services / controller / user / login 。 您可以使用此功能与端点保持一致。

We override the attemptAuthentication and successfulAuthentication methods of the UsernameAuthenticationFilter class.

我们覆盖UsernameAuthenticationFilter类的attemptAuthenticationsuccessfulAuthentication方法。

The attemptAuthentication function runs when the user tries to log in to our application. It reads the credentials, creates a user POJO from them, and then checks the credentials to authenticate.

当用户尝试登录我们的应用程序时,将运行tryAuthentication函数。 它读取凭据,从凭据创建用户POJO,然后检查凭据以进行身份​​验证。

We pass the username, password, and an empty list. The empty list represents the authorities (roles), and we leave it as is since we do not have any roles in our application yet.

我们传递用户名,密码和一个空列表。 空列表代表权限(角色),由于我们在应用程序中还没有任何角色,因此我们将其保留为原样。

If the authentication is successful, the successfulAuthentication method runs. The parameters of this method are passed by Spring Security behind the scenes.

如果身份验证成功,则运行successAuthentication方法。 Spring Security在后台传递了此方法的参数。

The attemptAuthentication method returns an Authentication object that contains the authorities we passed while attempting.

tryAuthentication方法返回一个Authentication对象,其中包含我们在尝试时传递的权限。

We want to return a token to user after authentication is successful, so we create the token using username, secret, and expiration date. We need to define the SECRET and EXPIRATION_DATE now.

我们希望在身份验证成功后将令牌返回给用户,因此我们使用用户名,机密和有效期创建令牌。 我们现在需要定义SECRETEXPIRATION_DATE

We create a class to be a container for our constants. You can set the secret to whatever you want, but the best practice is making the secret key as long as your hash. We use the HS256 algorithm in this example, so our secret key is 256 bits/32 chars.

我们创建一个类作为常量的容器。 您可以将密钥设置为所需的任意值,但是最佳实践是只要您的哈希值都是密钥。 在此示例中,我们使用HS256算法,因此我们的密钥为256位/ 32个字符。

The expiration time is set to 15 minutes, because it is the best practice against secret key brute-forcing attacks. The time is in milliseconds.

到期时间设置为15分钟,因为这是对付秘密密钥强行攻击的最佳实践。 时间以毫秒为单位。

We have prepared our Authentication filter, but it is not active yet. We also need an Authorization filter, and then we will apply them both through a configuration class.

我们已经准备好身份验证过滤器,但是它尚未激活。 我们还需要一个授权过滤器,然后我们将通过配置类将它们都应用。

This filter will check the existence and validity of the access token on the Authorization header. We will specify which endpoints will be subject to this filter in our configuration class.

该过滤器将检查授权标头上访问令牌的存在和有效性。 我们将在我们的配置类中指定哪些端点将受此过滤器的约束。

授权过滤器 (Authorization Filter)

The doFilterInternal method intercepts the requests then checks the Authorization header. If the header is not present or doesn’t start with “BEARER”, it proceeds to the filter chain.

doFilterInternal方法拦截请求,然后检查Authorization标头。 如果标题不存在或不以“ BEARER”开头,则它前进到过滤器链。

If the header is present, the getAuthentication method is invoked. getAuthentication verifies the JWT, and if the token is valid, it returns an access token which Spring will use internally.

如果存在标头,则调用getAuthentication方法。 getAuthentication验证JWT,如果令牌有效,它将返回Spring将在内部使用的访问令牌。

This new token is then saved to SecurityContext. You can also pass in Authorities to this token if you need for role-based authorization.

然后,此新令牌将保存到SecurityContext。 如果需要基于角色的授权,也可以将“权限”传递给此令牌。

Our filters are ready, and now we need to put them into action with the help of a configuration class.

我们的过滤器已经准备就绪,现在我们需要在配置类的帮助下将其付诸实践。

组态 (Configuration)

We annotate this class with @EnableWebSecurity and extend WebSecurityConfigureAdapter to implement our custom security logic.

我们使用@EnableWebSecurity注释此类,并扩展WebSecurityConfigureAdapter来实现我们的自定义安全逻辑。

We autowire the BCrypt bean that we defined earlier. We also autowire the UserDetailsService to find the user’s account.

我们自动连接我们先前定义的BCrypt bean。 我们还将自动连接UserDetailsS​​ervice以查找用户的帐户。

The most important method is the one which accepts an HttpSecurity object. Here we specify the secure endpoints and filters that we want to apply. We configure CORS, and then we permit all post requests to our sign up URL that we defined in the constants class.

最重要的方法是接受HttpSecurity对象的方法。 在这里,我们指定我们要应用的安全端点和过滤器。 我们配置CORS,然后允许所有发布请求到我们在常量类中定义的注册URL。

You can add other ant matchers to filter based on URL patterns and roles, and you can check this StackOverflow question for examples regarding that. The other method configures the AuthenticationManager to use our encoder object as its password encoder while checking the credentials.

您可以添加其他蚂蚁匹配器以根据URL模式和角色进行过滤,并且可以查看此StackOverflow问题以获取有关此示例的示例。 另一种方法将AuthenticationManager配置为在检查凭据时将我们的编码器对象用作其密码编码器。

测试中 (Testing)

Let’s send a few requests to test if it works properly.

让我们发送一些请求以测试其是否正常运行。

Here we send a GET request to access a protected resource. Our server responds with a 403 code. This is the expected behavior because we haven’t provided a token in the header. Now let’s create a user:

在这里,我们发送GET请求以访问受保护的资源。 我们的服务器以403代码响应。 这是预期的行为,因为我们没有在标头中提供令牌。 现在让我们创建一个用户:

To create a user, we send a post request with our User DTO data. We will use this user to login and get an access token.

要创建用户,我们发送带有用户DTO数据的发帖请求。 我们将使用该用户登录并获得访问令牌。

Great! We got the token. After this point, we will use this token to access protected resources.

大! 我们得到了令牌。 此后,我们将使用此令牌访问受保护的资源。

We provide the token in the Authorization header and we are now allowed access to our protected endpoint.

我们在Authorization标头中提供令牌,现在可以访问受保护的端点了。

结论 (Conclusion)

In this tutorial I have walked you through the steps I took when implementing JWT authorization and password authentication in Spring. We also learned how to save a user securely.

在本教程中,我向您介绍了在Spring中实现JWT授权和密码身份验证时所采取的步骤。 我们还学习了如何安全地保存用户。

Thank you for reading – I hope it was helpful to you. If you are interested in reading more content like this, feel free to subscribe to my blog at https://erinc.io. :)

感谢您的阅读-希望对您有所帮助。 如果您有兴趣此类内容,请随时通过https://erinc.io订阅我的博客。 :)

翻译自: https://www.freecodecamp.org/news/how-to-setup-jwt-authorization-and-authentication-in-spring/

如何设置Java Spring Boot JWT授权和认证相关推荐

  1. Spring Boot JWT 快速入门

    本章节讨论 jwt 在 spring boot 中的应用.意在快速入门 jwt. java jdk1.8 maven 3.2+ spring boot 2.0+ JSON Web Token(JWT) ...

  2. Java+Spring Boot 二手书交易系统

    目录 1 系统简介 2 系统相关技术 2.1 Java EE 2.2 Springboot框架 2.3 Maven技术 2.4 Tomcat服务器 2.5 MySQL 3 需求分析 3.1 需求概述 ...

  3. JAVA Spring Boot与海康威视摄像头的故事

    <菜鸟学JAVA第一篇> 前言:JAVA Spring Boot与海康威视摄像头的故事 关于本贴 干货部分 进入官网,选择sdk下载: 下载所需要的开发包(以下教程以windows为例): ...

  4. 【直播回顾】云栖社区特邀专家徐雷Java Spring Boot开发实战系列课程(第19讲):Java Spring Cloud微服务架构模式与开发实战...

    主讲人:徐雷(云栖社区特邀Java专家) 徐雷,花名:徐雷frank:资深架构师,MongoDB中文社区联席主席,吉林大学计算机学士,上海交通大学硕士.从事了 10年+开发工作,专注于分布式架构,Ja ...

  5. Java Spring Boot VS .NetCore (七) 配置文件

    Java Spring Boot VS .NetCore (一)来一个简单的 Hello World Java Spring Boot VS .NetCore (二)实现一个过滤器Filter Jav ...

  6. Java Spring Boot 2.0 实战之制作Docker镜像并推送到Docker Hub和阿里云仓库

    内容摘要:大规模集群快速部署Java应用,需要制作Docker镜像,本次课程详细介绍如何制作Java程序的Docker镜像文件,深入解析DockerFile核心参数,以及实践演练把我们制作的Docke ...

  7. 前后端分离的用户验证原理及Spring Boot + JWT的框架搭建(附完整的框架代码)之二

    本篇承接上一篇,关于Session以及JWT Token参考: 前后端分离的用户验证原理及Spring Boot + JWT的框架搭建(附完整的框架代码)之一 框架整体描述 框架使用Spring Bo ...

  8. 云栖社区特邀专家徐雷——Java Spring Boot开发实战系列课程【往期直播回顾】...

    徐雷,花名:徐雷frank:资深架构师,MongoDB中文社区联席主席,吉林大学计算机学士,上海交通大学硕士.从事了 10年+开发工作,专注于分布式架构,Java Spring Boot.Spring ...

  9. 毕设项目——智慧小区系统(Java Spring Boot+Vue ElementUI)

    毕设项目--智慧小区系统(Java Spring Boot+Vue ElementUI) 项目初衷(最真实版) 系统技术分析 前端界面 后端及数据库 系统功能介绍 小区业主端 物业人员端 系统界面展示 ...

最新文章

  1. 开源贡献 计算_如何克服恐惧并为开源做贡献
  2. GPU高性能编程CUDA实战(二)
  3. 阮一峰 《ECMAScript 6 入门》:let 和 const 命令
  4. oracle back log,11g闪回日志(flashback log)保留时间参数 - db_flashback_retention_target
  5. Codeforces 1103 E. Radix sum
  6. 解决react状态管理---React Query
  7. 【翻译】AdaIN:Arbitrary Style Transfer in Real-time with Adaptive Instance Normalization
  8. Linux vmstat命令实战详解
  9. python 显示gif_使用tkinter显示动态gif
  10. 线性表的链式存储结构(C语言实现)
  11. 沙龙回顾 | 从开发平台到智能供应链,AI技术如何推动企业智能化升级?
  12. php resque demo,php-resque 极简php消息队列
  13. 1896-2021历届奥运会奖牌榜动态排序(Matplotlib图表动画)
  14. 运维学习之lvm(逻辑卷管理)
  15. Soft Filter Pruning(SFP)算法笔记
  16. CMake I 获取/设置编译器
  17. 论文解读:PF磷酸:基于机器学习的磷酸化位点预测疟原虫蛋白的工具
  18. Netty 工作流程图梳理
  19. 微信小程序开发之全屏显示
  20. 毕业一年的大专生程序员工作总结(java后台)

热门文章

  1. 哈夫曼树的生成及哈夫曼编码
  2. 【Linux】Linux computer文件夹下各种文件的作用
  3. python 使用安装虚拟环境 virtualenv
  4. 交换机启用光口命令_如何在思科交换机上查询光模块状态?
  5. 算法(1)斐波那契数列
  6. iOS-仿膜拜贴纸滚动(物理仿真)
  7. 明文存密码成惯例?Facebook 6 亿用户密码可被 2 万员工直接看
  8. java 冒泡排序和快速排序 实现
  9. sersync 同步
  10. 在Ubuntu下FFmpeg编译,支持x264和x265(HECV)