SpringSecurity+Redis认证过程小结

下面是完整的SpringSecurity+Redis认证过程攻略。

准备工作

要进行SpringSecurity+Redis认证,我们需要先进行一些准备工作。具体包括:

  1. 搭建好Spring项目,并引入相应的依赖库,如SpringSecurity和Redis。
  2. 配置好SpringSecurity,包括配置安全过滤器、权限控制等内容。
  3. 安装配置好Redis,确保项目可以连接到Redis数据库。

默认情况下,SpringSecurity在进行认证时,会将用户信息放在Session中。但是Session中的数据是存放在内存中的,如果应用发生重启或者集群环境下,会导致认证信息丢失,因此需要使用Redis来存储认证信息。

认证过程

接下来,我们就来具体讲解SpringSecurity+Redis认证的过程。整个认证过程可以分为以下几个步骤:

  1. 用户登录,输入用户名和密码。
  2. SpringSecurity根据用户名查询并获取用户的信息。
  3. SpringSecurity将用户信息存储到Redis中,并生成token作为认证凭据。
  4. 将token返回给用户。
  5. 用户在后续的页面请求中需要携带该token,以证明自己的身份。
  6. 验证该token是否有效,有则可以访问受保护的资源,无则需要重新进行认证。

下面针对这些步骤进行详细的讲解。

1. 用户登录

用户输入用户名和密码,点击登录按钮进行登录操作。登录页面的代码示例如下:

<!DOCTYPE html>
<html>
  <head>
    <title>Login Page</title>
  </head>
  <body>
    <h1>Login Page</h1>
    <form method="post" action="/login">
      <p>
        <label>User Name:</label>
        <input type="text" name="username" />
      </p>
      <p>
        <label>Password:</label>
        <input type="password" name="password" />
      </p>
      <button type="submit">Log in</button>
    </form>
  </body>
</html>

2. 获取用户信息

用户在登录页面输入用户名和密码后,SpringSecurity会根据用户名查询并获取用户的信息。这一步需要在自定义UserDetailsService实现类中完成。具体代码示例如下:

@Service
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在!");
        }

        List<GrantedAuthority> authorities = new ArrayList<>();
        // 为用户授权
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));

        return new org.springframework.security.core.userdetails.User(
                user.getUsername(), user.getPassword(), authorities);
    }
}

3. 存储用户信息到Redis

获取用户信息后,SpringSecurity会将用户信息存储到Redis中,并生成token作为认证凭据。生成token的代码示例如下:

@Service
public class TokenServiceImpl implements TokenService {

    private static final long EXPIRATION_TIME = 60 * 60 * 24 * 7; // 1 week in seconds
    private static final String SECRET = "ThisIsASecret"; // TODO: update this with real secret

    @Override
    public String generateToken(UserDetails user) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("sub", user.getUsername());
        claims.put("iat", new Date().getTime() / 1000);
        claims.put("exp", new Date().getTime() / 1000 + EXPIRATION_TIME);

        return Jwts.builder()
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .compact();
    }
}

4. 返回token给用户

token生成后,SpringSecurity会将token返回给用户。示例代码如下:

@Service
public class TokenAuthenticationService {

    private static final String AUTH_HEADER_NAME = "X-AUTH-TOKEN";

    public void addTokenToResponse(HttpServletResponse response, String token) {
        response.addHeader(AUTH_HEADER_NAME, token);
    }

    public Authentication getAuthentication(HttpServletRequest request) {
        String token = request.getHeader(AUTH_HEADER_NAME);
        if (token != null) {
            // parse the token and extract the user details
            UserDetails userDetails = getUserDetailsFromToken(token);
            if (userDetails != null) {
                return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            }
        }
        return null;
    }

    private UserDetails getUserDetailsFromToken(String token) {
        try {
            Jws<Claims> claims = Jwts.parser()
                    .setSigningKey(SECRET)
                    .parseClaimsJws(token);

            String username = claims.getBody().getSubject();
            List<SimpleGrantedAuthority> authorities = new ArrayList<>();
            // TODO: populate the authorities list based on the user roles

            return new org.springframework.security.core.userdetails.User(
                    username, "", authorities);
        } catch (JwtException ex) {
            // TODO: handle the exception
        }
        return null;
    }
}

5. 携带token访问资源

用户在后续的页面请求中需要携带该token,以证明自己的身份。示例代码如下:

curl -H "X-AUTH-TOKEN: eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ1c2VyMSIsImlhdCI6MTYwMzgxMzc2MywiZXhwIjoxNjAzODE4MjczfQ.m8HlDKBQKLP5Fa2CYQQatbJV5Rhif2HCJyVZtSxHTorFV6ZF8JL420kC-XtWZDG_Qd5I_Y0cg9ul1PDg0qApFQ" http://localhost:8080/api/user/1

6. 验证token

用户携带token访问受保护的资源时,需要验证该token是否有效,如果有效则可以访问资源,否则需要重新进行认证。示例代码如下:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsService userDetailsService;

    @Autowired
    private TokenAuthenticationService tokenAuthenticationService;

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/api/user/**").authenticated()
                .anyRequest().permitAll()
                .and()
                .addFilterBefore(new TokenAuthenticationFilter(tokenAuthenticationService, userDetailsService, redisConnectionFactory), BasicAuthenticationFilter.class);
    }
}

上述代码中,我们配置了一个TokenAuthenticationFilter类来验证token的有效性。TokenAuthenticationFilter的代码示例如下:

public class TokenAuthenticationFilter extends OncePerRequestFilter {

    private static final Logger log = LoggerFactory.getLogger(TokenAuthenticationFilter.class);

    private final TokenAuthenticationService tokenAuthenticationService;
    private final UserDetailsService userDetailsService;
    private final RedisConnectionFactory redisConnectionFactory;

    public TokenAuthenticationFilter(TokenAuthenticationService tokenAuthenticationService, UserDetailsService userDetailsService, RedisConnectionFactory redisConnectionFactory) {
        this.tokenAuthenticationService = tokenAuthenticationService;
        this.userDetailsService = userDetailsService;
        this.redisConnectionFactory = redisConnectionFactory;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = request.getHeader("X-AUTH-TOKEN");
        if (token != null) {
            String username = getUsernameFromToken(token);
            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                if (validateToken(token, userDetails)) {
                    TokenBasedAuthentication authentication = new TokenBasedAuthentication(userDetails, token);
                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            }
        }
        filterChain.doFilter(request, response);
    }

    private String getUsernameFromToken(String authToken) {
        try {
            return Jwts.parser()
                    .setSigningKey(SECRET)
                    .parseClaimsJws(authToken)
                    .getBody()
                    .getSubject();
        } catch (JwtException ex) {
            log.error("Error parsing token: {}", authToken);
        }
        return null;
    }

    private boolean validateToken(String token, UserDetails userDetails) {
        String storedToken = redisConnectionFactory.getConnection().get(userDetails.getUsername());
        return storedToken != null && storedToken.equals(token);
    }
}

至此,SpringSecurity+Redis认证过程就讲解完了。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringSecurity+Redis认证过程小结 - Python技术站

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

相关文章

  • 什么是Java永久代(PermGen)?

    Java永久代(PermGen)是Java虚拟机(JVM)中的一部分,它是用于存储类和静态变量等元数据的特殊区域。下面将对Java永久代进行详细的使用攻略。 标题一:Java永久代的概念 什么是Java永久代? Java永久代是JVM的一部分,用于存储Java类的元数据和静态变量。与Java堆不同,永久代的生命周期与JVM相同。在JVM启动时,会预先分配一定…

    Java 2023年5月11日
    00
  • 如何通过一张图搞懂springBoot自动注入原理

    下面是关于“如何通过一张图搞懂springBoot自动注入原理”的完整攻略。 1. 简介 在 Spring Boot 中,我们可以使用自动配置完成很多操作,其中最重要的一个就是通过自动注入来维护 Spring 应用程序之间的依赖关系。 Spring Boot 中自动注入的原理比较复杂,但我们可以用一张图来概述它的过程。 2. 图片介绍 下面这张图片展示了自动…

    Java 2023年5月15日
    00
  • java实现读取、删除文件夹下的文件

    关于Java实现读取、删除文件夹下的文件的攻略,可以分为两个步骤:读取和删除文件。 1. 读取文件 Java中读取文件需要使用File类,它提供了各种方法来处理文件和文件夹。使用File类的方法之一是listFiles(),该方法用于获取在文件夹中的所有文件和文件夹的列表。我们可以使用该方法获得要操作的文件夹下面的所有文件或文件夹。 以下是一个读取文件夹下所…

    Java 2023年5月20日
    00
  • 如何通过Java代码实现KMP算法

    下面我将为你讲解“如何通过Java代码实现KMP算法”的完整攻略。 1. 什么是KMP算法? KMP算法是一种字符串匹配算法,其全称是Knuth-Morris-Pratt算法,其主要思想是在匹配过程中充分利用已知信息,尽可能地减少比较次数,从而达到快速匹配的目的。 2. KMP算法的实现过程 2.1 计算字符串的next数组 在KMP算法中,关键在于如何计算…

    Java 2023年5月18日
    00
  • js创建jsonArray传输至后台及后台全面解析

    请看下面的攻略: 客户端(js)创建jsonArray并传输至服务端 创建jsonArray 1.定义一个空的jsonArray: var jsonArray = []; 2.向jsonArray中添加数据: var jsonArray = []; for (var i = 0; i < 3; i++) { var jsonObj = { name: …

    Java 2023年5月26日
    00
  • springboot如何为web层添加统一请求前缀

    为web层添加统一请求前缀可以通过Spring Boot提供的@RestControllerAdvice注解来实现,具体步骤如下: 步骤1:添加@RestControllerAdvice注解 在包含@Controller注解的基础类上添加@RestControllerAdvice注解,如下所示: @RestControllerAdvice public cl…

    Java 2023年6月16日
    00
  • vscode搭建java开发环境的实现步骤

    以下是VS Code搭建Java开发环境的实现步骤。 环境要求 VS Code Java开发工具包(JDK) VS Code插件:Java Extension Pack 步骤一:安装JDK 在官方网站 下载JDK,根据自己电脑的系统选择对应的JDK版本进行下载和安装。 安装完成后,配置JAVA_HOME环境变量,将其指向JDK的安装目录。 步骤二:安装VS …

    Java 2023年5月19日
    00
  • Android Java crash 处理流程详解

    下面我来为你详细讲解“Android Java crash 处理流程详解”的完整攻略。 Android Java crash 处理流程详解 在Android开发中,我们经常会遇到应用程序由于各种原因而崩溃的情况。此时,我们需要进行相应的处理操作,才能有效减少应用程序的异常崩溃情况,提高用户体验。本文将详细介绍Android Java crash的处理流程,帮…

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