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日

相关文章

  • myeclipse的快捷键小结与myeclipse快捷键设置方法分享

    一、MyEclipse快捷键的小结首先需要介绍的是MyEclipse中的快捷键。快捷键是软件开发中非常重要的一部分,使用好快捷键可以大大提高开发效率,而MyEclipse也提供了非常丰富的快捷键功能。下面就来为大家介绍一些常用的MyEclipse快捷键: Ctrl + S:保存当前文件 Ctrl + C:复制选中的内容 Ctrl + V:粘贴剪切板中的内容 …

    Java 2023年6月15日
    00
  • jQuery解析XML文件同时动态增加js文件的方法

    首先需要明确的是,jQuery提供了内置的函数来实现解析XML文件和动态增加js文件。下面是详细的操作步骤。 解析XML文件 步骤一:通过ajax方法获取XML数据 使用jQuery的ajax方法,通过URL链接获取XML数据。使用ajax方法时,需要设置dataType为xml。 $.ajax({ url: ‘xml/your_xml_file.xml’,…

    Java 2023年6月15日
    00
  • SpringMVC适配器模式代码示例

    简介 在SpringMVC中,适配器模式用于将请求转换为处理程序方法。本文将介绍SpringMVC适配器模式的代码示例,并提供两个示例说明。 SpringMVC适配器模式 SpringMVC适配器模式是一种设计模式,用于将请求转换为处理程序方法。在SpringMVC中,适配器模式由HandlerAdapter接口和其实现类来实现。以下是一个使用适配器模式的示…

    Java 2023年5月17日
    00
  • java取两个字符串的最大交集

    Java取两个字符串的最大交集的算法可以通过动态规划(Dynamic Programming)来实现,其中最长公共子串(Longest Common Substring, LCS)就是该问题的一个特例。 以下是完整的攻略: 步骤1:定义状态 定义一个二维数组 dp[i][j],表示字符串 a 的前 i 个字符和字符串 b 的前 j 个字符的最长公共子串长度。…

    Java 2023年5月27日
    00
  • Dubbo服务校验参数的解决方案

    Dubbo服务校验参数的解决方案 Dubbo服务是一种面向服务架构(SOA)的分布式服务框架,支持远程过程调用(RPC)与服务治理。 在Dubbo服务中,服务提供者与消费者之间的参数校验是非常关键的一环。为了保证系统的稳定性和安全性,我们需要对参数进行校验,从而减少不必要的代码运行错误和请求风险。 以下是Dubbo服务校验参数的解决方案: 1. 使用JSR …

    Java 2023年5月19日
    00
  • Java Swing最详细基础知识总结

    Java Swing最详细基础知识总结 什么是Java Swing Java Swing是一个GUI工具包,用于在Java应用程序中创建可视化用户界面。它提供了许多功能强大的组件,包括按钮、文本框、标签和表格等,使得我们可以快速方便的创建GUI界面,对于Java开发者来说是非常重要的工具。 Java Swing组件 Java Swing提供了许多GUI组件,…

    Java 2023年5月26日
    00
  • maven利用tomcat插件部署远程Linux服务器的步骤详解

    Ok,首先需要确定一下使用的环境:Linux服务器、maven、tomcat。接下来就可以开始步骤了。 步骤 在Linux服务器上安装 tomcat以及在本地机器上安装maven。 配置tomcat用户,执行如下命令添加一个名为tomcat的用户并设置密码。 useradd tomcat passwd tomcat 配置maven的settings.xml文…

    Java 2023年6月2日
    00
  • spring boot的健康检查HealthIndicators实战

    下面我将详细讲解关于 “spring boot的健康检查HealthIndicators实战” 的完整攻略: 1. 什么是 HealthIndicators HealthIndicators 是 Spring Boot 中提供的健康检查指示器,可以通过实现 HealthIndicator 接口并返回一个 Health 对象来表示应用程序的健康状态。Healt…

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