下面我会为您介绍如何使用Spring Boot和Redis实现Token权限认证。
为什么使用Token认证?
在Web应用程序中,为了保护页面和API,需要用户进行登录并验证其身份。其中一种常用的方法是使用Token认证。在Token认证中,用户首先输入用户名和密码进行登录,验证成功后,服务器会返回一个Token令牌,将其存储在客户端。随后,客户端将该Token在每次请求时发送给服务器,服务器会解码Token并验证是否有效,从而决定是否授权该操作。
Token认证的优点包括:
- 不需要存储Session状态,因此可以扩展到多台服务器集群。
- 客户端可以自主管理Token,不需要强制退出。
- 可以支持不同的身份验证策略(例如直接验证或者OAuth认证)。
实现流程
接下来我们将使用SpringBoot和Redis实现Token权限认证,实现的流程如下:
- 用户输入用户名和密码进行登录。
- 服务器验证用户名和密码是否正确。
- 若验证成功,则生成一个Token并存储在Redis中。
- 服务器将该Token返回给客户端。
- 客户端在每次请求时将该Token作为HTTP头部的Authorization属性值发送给服务器。
- 服务器解析该Token,并验证其有效性。
- 验证成功后,服务器授权该操作。
实现步骤
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技术站