如何设置Java Spring Boot JWT授权和认证

news/2024/7/2 21:23:59

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/


http://lihuaxi.xjx100.cn/news/237189.html

相关文章

EOS共识机制——DPoS代理权益证明

链客&#xff0c;专为开发者而生&#xff0c;有问必答&#xff01; 此文章来自区块链技术社区&#xff0c;未经允许拒绝转载。 区块链共识机制与它的演进&#xff0c;是由于区块链式去中心化而且分布式的系统&#xff0c;必须要有一套放诸四海皆准类似宪法的规则&#xff0c;来…

docker的用法

Docker是开发人员和系统管理员构建&#xff0c;发布和运行分布式应用程序的开放平台&#xff0c;可以在笔记本电脑、数据中心、虚拟机还有云服务器上运行。 使用Docker工具来提高生产率的方法&#xff1a;本地依赖&#xff1a;你需要在本地系统上快速试用 magento 吗&#xff1…

前端面试的作品示例_如何回答任何技术面试问题-包括示例

前端面试的作品示例Technical interviews can be extremely daunting. From the beginning of each question to the end, its important to know what to expect, and to be aware of the areas you might be asked about. 技术面试可能会非常艰巨。 从每个问题的开始到结束&a…

Win10 下 RabbitMQ 的 安装 配置

记录下本人在win10环境下安装RabbitMQ的步骤&#xff0c;以作备忘。 第一步&#xff1a;下载并安装erlang 原因&#xff1a;RabbitMQ服务端代码是使用并发式语言Erlang编写的&#xff0c;安装Rabbit MQ的前提是安装Erlang。下载地址&#xff1a;http://www.erlang.org/download…

智能合约和区块链技术:入门指南

链客&#xff0c;专为开发者而生&#xff0c;有问必答&#xff01; 此文章来自区块链技术社区&#xff0c;未经允许拒绝转载。 智能合约和区块链技术&#xff1a;入门指南 多年前&#xff0c;在没有数字合约和区块链技术存在的情况下&#xff0c;双方的合约往往以传统的方式进…

node/js 漏洞_6个可用于检查Node.js中漏洞的工具

node/js 漏洞Vulnerabilities can exist in all products. The larger your software grows, the greater the potential for vulnerabilities. 所有产品中都可能存在漏洞。 您的软件增长得越大&#xff0c;潜在的漏洞就越大。 Vulnerabilities create opportunities for expl…

什么是网络爬虫,网络爬虫有什么用?

什么是网络爬虫&#xff0c;网络爬虫有什么用&#xff1f; 简单地说&#xff0c;就是把网页所展示数据通过非人工的手段获取下来。 现在是大数据时代&#xff0c;数据分析是解决各行各业相关问题重要的依据。数据分析结果的准确性有很大一部分取决于数据量是否足够大。如果是几…

aws fargate_我如何在AWS Fargate上部署#100DaysOfCloud Twitter Bot

aws fargateAfter passing my last certification, I asked myself how much time I spent studying cloud computing.通过上一份认证后&#xff0c;我问自己自己花了多少时间研究云计算。 More than 100 days!超过100天&#xff01; It also made me realize two things:这也…