SpringBoot和Redis实现Token权限认证的实例讲解

下面我会为您介绍如何使用Spring Boot和Redis实现Token权限认证。

为什么使用Token认证?

在Web应用程序中,为了保护页面和API,需要用户进行登录并验证其身份。其中一种常用的方法是使用Token认证。在Token认证中,用户首先输入用户名和密码进行登录,验证成功后,服务器会返回一个Token令牌,将其存储在客户端。随后,客户端将该Token在每次请求时发送给服务器,服务器会解码Token并验证是否有效,从而决定是否授权该操作。

Token认证的优点包括:

  • 不需要存储Session状态,因此可以扩展到多台服务器集群。
  • 客户端可以自主管理Token,不需要强制退出。
  • 可以支持不同的身份验证策略(例如直接验证或者OAuth认证)。

实现流程

接下来我们将使用SpringBoot和Redis实现Token权限认证,实现的流程如下:

  1. 用户输入用户名和密码进行登录。
  2. 服务器验证用户名和密码是否正确。
  3. 若验证成功,则生成一个Token并存储在Redis中。
  4. 服务器将该Token返回给客户端。
  5. 客户端在每次请求时将该Token作为HTTP头部的Authorization属性值发送给服务器。
  6. 服务器解析该Token,并验证其有效性。
  7. 验证成功后,服务器授权该操作。

实现步骤

1. 创建Spring Boot项目

首先,我们需要创建一个Spring Boot项目。可以使用https://start.spring.io/创建项目。本例中,我们需要选中Web、Redis和Security模块。

2. 创建一个登录页面

在src/main/resources/templates目录下,创建一个login.html文件,用于显示登录页面。以下是该文件的代码:

<!DOCTYPE html>
<html>
    <head>
        <title>登录</title>
    </head>
    <body>
        <div>
            <h3>登录</h3>
            <form method="post" action="/login">
                <div>
                    <label for="username">用户名:</label>
                    <input type="text" id="username" name="username">
                </div>
                <div>
                    <label for="password">密码:</label>
                    <input type="password" id="password" name="password">
                </div>
                <div>
                    <button type="submit">登录</button>
                </div>
            </form>
        </div>
    </body>
</html>

3. 创建一个登录Controller

在src/main/java目录下,创建一个名为LoginController的类,用于处理用户登录请求。以下是该类的代码:

@RestController
public class LoginController {
    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @PostMapping("/login")
    public ResponseEntity<String> login(@RequestParam String username,
                                         @RequestParam String password) {
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);

        if (userDetails == null || !passwordEncoder.matches(password, userDetails.getPassword())) {
            return new ResponseEntity<>("用户或密码不正确", HttpStatus.FORBIDDEN);
        }

        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, username);

        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization", token);

        return new ResponseEntity<>(headers, HttpStatus.OK);
    }
}

首先,该类使用@Autowired注解自动注入了UserDetailsService、PasswordEncoder和StringRedisTemplate对象。

在login方法中,通过调用userDetailsService对象的loadUserByUsername方法,获取用户对应的UserDetails对象。接着,通过调用passwordEncoder对象的matches方法,比较用户输入的密码和UserDetails对象中的密码是否匹配。

如果匹配失败,返回HTTP状态码403。如果匹配成功,生成一个唯一的Token(使用UUID),将用户名和Token存储在Redis中。最后,依照HTTP协议规范,将这个Token作为HTTP头部的Authorization属性值返回给客户端。

4. 创建Token过滤器

在src/main/java目录下,创建一个名为TokenFilter的类,用于拦截客户端请求并验证是否有权限进行该操作。以下是该类的代码:

public class TokenFilter extends OncePerRequestFilter {
    private static final String HEADER_AUTHORIZATION = "Authorization";

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = request.getHeader(HEADER_AUTHORIZATION);
        if (token != null) {
            String username = redisTemplate.opsForValue().get(token);
            if (username != null) {
                SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(username, null, Collections.emptyList()));
            }
        }

        filterChain.doFilter(request, response);
    }
}

首先,该类使用@Autowired注解自动注入了StringRedisTemplate对象。

在doFilterInternal方法中,该过滤器会从请求头部中获取Authorization属性值(即Token)。接着,它会使用这个Token从Redis中获取对应的用户名。如果找到了用户名,就将该用户名存入SecurityContext中,并授权该操作。

5. 配置Security

在src/main/java目录下,创建一个名为SecurityConfig的类,用于配置Spring Security。以下是该类的代码:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests().anyRequest().authenticated()
                .and().addFilterBefore(new TokenFilter(), UsernamePasswordAuthenticationFilter.class)
                .formLogin().loginPage("/login").loginProcessingUrl("/login").permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
    }
}

首先,该类使用@Autowired注解自动注入了UserDetailsService和PasswordEncoder对象。

在configure方法中,该类关闭了CSRF保护,并允许所有请求进行身份验证。接着,它添加了一个TokenFilter过滤器,并将其放在了UsernamePasswordAuthenticationFilter过滤器之前。最后,它配置了一个form表单进行登录,并指定了登录页面的地址。

在configure(AuthenticationManagerBuilder auth)方法中,该类将自定义的UserDetailsService以及PasswordEncoder注册到了AuthenticationManagerBuilder中。

6. 创建测试Controller

在src/main/java目录下,创建一个名为TestController的类,用于测试Token认证是否生效。以下是该类的代码:

@RestController
public class TestController {
    @GetMapping("/hello")
    public String hello() {
        return "hello, world!";
    }
}

7. 配置Redis

在src/main/java目录下,创建一个名为RedisConfig的类,用于配置Redis连接。以下是该类的代码:

@Configuration
public class RedisConfig {
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory("localhost", 6379);
    }

    @Bean
    public RedisTemplate<?, ?> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<byte[], byte[]> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        return template;
    }

    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(connectionFactory);
        return template;
    }
}

这个类使用@Bean注解声明了一个RedisConnectionFactory对象,并将其连接到了本地的6379端口。接着,声明了redisTemplate和stringRedisTemplate对象,并将其注册到Spring IoC容器中。

8. 测试

至此,我们已经完成了所有的代码编写。现在可以启动应用程序,并访问http://localhost:8080/login页面。输入用户名和密码后,将返回一个Token。使用Postman或者浏览器发送一个HTTP GET请求到http://localhost:8080/hello,将Authorization属性设置为该Token即可。如果Token验证通过,将返回"hello, world!"字符串。

示例1:curl测试http://localhost/login登录,并返回token

curl --location --request POST 'http://localhost:8080/login' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'username=admin' \
--data-urlencode 'password=admin'

输出:
"Authorization: c4852673-a86f-4c18-a5ae-54494ca9a1b3"

示例2:使用curl测试http://localhost/hello

curl --location --request GET 'http://localhost:8080/hello' \
--header 'Authorization: c4852673-a86f-4c18-a5ae-54494ca9a1b3'

输出:
"hello, world!"

综上所述,以上就是使用SpringBoot和Redis实现Token权限认证的实例讲解,包括了创建登录页面、创建登录Controller、创建Token过滤器、配置Security、创建测试Controller、配置Redis、测试Token认证等多个步骤。通过学习本文,读者可以了解到如何使用Spring Boot和Redis搭建一个Token认证服务,并在Web应用程序中进行使用。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot和Redis实现Token权限认证的实例讲解 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • 有趣的JavaScript隐式类型转换操作实例分析

    下面是“有趣的JavaScript隐式类型转换操作实例分析”的完整攻略。 1. 什么是隐式类型转换 在JavaScript中,操作符通常期望得到一个具有特定数据类型的值。如果表达式的实际值类型与期望的不同,那么JavaScript会自动将它转换为期望的类型,这就是隐式类型转换。 2. 实例分析 下面将用两条实例来详细讲解隐式类型转换操作。 实例一:字符串加上…

    Java 2023年5月26日
    00
  • java进阶之了解SpringBoot的配置原理

    Java进阶之了解Spring Boot的配置原理 Spring Boot是一个非常流行的Java开发框架,它可以帮助我们快速搭建Web应用程序。在使用Spring Boot时,我们需要了解其配置原理,以便更好地理解其工作原理。本文将介绍Spring Boot的配置原理,包括自动配置、条件注解、配置文件等。 1. 自动配置 Spring Boot的自动配置是…

    Java 2023年5月14日
    00
  • java使用Feign实现声明式Restful风格调用

    Java 的 Feign 库提供了一种声明式的 RESTful 风格的调用方法,可以让我们更加便捷地进行服务调用。下面是使用 Feign 实现声明式 RESTful 风格调用的完整攻略。 什么是 Feign Feign 是 Netflix 开源的一种声明式、模板化的 HTTP 客户端,它的主要作用就是让开发者更加方便的调用 RESTful 风格的 API。 …

    Java 2023年5月31日
    00
  • Springboot插件开发实战分享

    SpringBoot插件开发实战分享 SpringBoot插件是一种可扩展的机制,可以帮助我们扩展SpringBoot的功能。本文将详细讲解SpringBoot插件开发的完整攻略,并提供两个示例。 1. 创建SpringBoot插件 在SpringBoot中,我们可以使用Maven或Gradle来创建SpringBoot插件。以下是一个简单的Maven插件示…

    Java 2023年5月15日
    00
  • 2019年MyBatis面试高频题(面试宝典)

    2019年MyBatis面试高频题(面试宝典)的完整攻略 什么是MyBatis? MyBatis是一种基于Java语言的持久化框架,这种框架通过XML文件或注解将Java对象和SQL语句进行映射,从而完成数据库操作。 MyBatis的特点是什么? MyBatis的特点主要包括以下三个方面: 灵活:MyBatis允许使用XML文件或注解进行映射,同时也支持动态…

    Java 2023年5月20日
    00
  • Java 数据结构之时间复杂度与空间复杂度详解

    Java 数据结构之时间复杂度与空间复杂度详解 什么是时间复杂度和空间复杂度 在了解时间复杂度和空间复杂度之前,我们需要先了解一下什么是复杂度。 在计算机科学中,复杂度是指算法的性能指标,主要包括时间复杂度和空间复杂度。 时间复杂度是指算法在执行过程中所需要的时间资源,通常用执行次数来表示,也被称为算法的渐进时间复杂度。 空间复杂度是指算法在执行过程中所需要…

    Java 2023年5月26日
    00
  • Java生成和解析XML格式文件和字符串的实例代码

    下面我将详细讲解“Java生成和解析XML格式文件和字符串的实例代码”的完整攻略以及其中的两个示例。 1. 什么是XML XML是可扩展标记语言(Extensible Markup Language)的缩写,它是一种用于传输和存储数据的标准格式。XML是自我描述、可扩展的,可以通过文本编辑器或工具生成并解析。在Java应用程序中,XML是一种常见的数据交换格…

    Java 2023年5月20日
    00
  • java组件smartupload实现上传文件功能

    下面是关于“java组件smartupload实现上传文件功能”的完整攻略,包含两个示例。 SmartUpload 简介 SmartUpload 是一个 Java 组件,能够方便地实现上传文件的功能。它提供了上传文件的基本方法,并可以使用 Java 类库自身的方法来读取这些文件。SmartUpload 支持批量上传,支持上传时的文件类型检查等功能。 Smar…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部