Spring Boot单点登录实践

这篇具有很好参考价值的文章主要介绍了Spring Boot单点登录实践。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

在现代的Web应用程序中,单点登录(Single Sign-On)已经变得越来越流行。单点登录使得用户只需要一次认证即可访问多个应用程序,同时也提高了应用程序的安全性。Spring Boot作为一种广泛使用的Web开发框架,在单点登录方面也提供了很好的支持。

在本文中,我们将使用Spring Boot构建一个基本的单点登录系统。我们将介绍如何使用Spring Security和JSON Web Tokens(JWTs)来实现单点登录功能。本文假设您已经熟悉Spring Boot和Spring Security。

什么是JWT?

在介绍实现单点登录之前,让我们先了解一下JWT。JWT是一种基于JSON格式的开放标准(RFC 7519),用于在不同的应用程序之间安全地传输信息。它由三个部分组成:

  • 标头(Header):包含JWT的类型和使用的签名算法。
  • 负载(Payload):包含实际的信息。
  • 签名(Signature):使用私钥生成的签名,用于验证JWT的真实性。

JWT通常在身份验证过程中使用,以便在不需要存储用户信息的情况下验证用户身份。由于JWT是基于标准化的JSON格式构建的,因此在多种编程语言中都可以轻松地实现和解析。

实现单点登录

下面我们来介绍如何使用JWT实现基本的单点登录系统。这个系统由两个应用程序组成:认证应用程序和资源应用程序。用户在认证应用程序上进行一次身份验证之后,就可以访问资源应用程序。

认证应用程序

我们首先需要构建一个认证应用程序,用于认证用户信息并生成JWT。

添加依赖

首先,我们需要添加以下依赖:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

<dependency>
  <groupId>io.jsonwebtoken</groupId>
  <artifactId>jjwt</artifactId>
  <version>0.9.1</version>
</dependency>

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
  • spring-boot-starter-security:用于提供基本的安全性支持。
  • jjwt:JSON Web Token的Java实现。
  • spring-boot-starter-web:用于提供Web应用程序支持。
配置Spring Security

接下来,我们需要配置Spring Security。我们将使用Spring Security的默认配置,并添加一个自定义的UserDetailsService来从数据库中加载用户信息。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private UserDetailsService userDetailsService;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .csrf().disable()
      .authorizeRequests()
        .antMatchers("/auth/**").permitAll()
        .anyRequest().authenticated()
      .and().formLogin()
        .loginPage("/auth/login")
        .successHandler(authenticationSuccessHandler())
        .failureHandler(authenticationFailureHandler())
        .permitAll()
      .and().logout()
        .logoutUrl("/auth/logout")
        .logoutSuccessUrl("/auth/login?logout")
        .invalidateHttpSession(true)
        .deleteCookies("JSESSIONID");
  }

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

  @Bean
  public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }

  @Bean
  public AuthenticationSuccessHandler authenticationSuccessHandler() {
    return new JWTAuthenticationSuccessHandler();
  }

  @Bean
  public AuthenticationFailureHandler authenticationFailureHandler() {
    return new JWTAuthenticationFailureHandler();
  }

}

在上述配置中,我们定义了一个路由表达式"/auth/**"允许匿名访问,这意味着认证应用程序的登录和注册页面可以被未经身份验证的用户访问。我们还定义了自定义的AuthenticationSuccessHandler和AuthenticationFailureHandler,用于在用户身份验证成功或失败时生成JWT并将其返回给用户。这些处理程序将在下一步中实现。

实现自定义的AuthenticationSuccessHandler和AuthenticationFailureHandler

在上述配置中,我们使用了自定义的AuthenticationSuccessHandler和AuthenticationFailureHandler。让我们来实现它们。

public class JWTAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

  private static final String JWT_SECRET = "secret";
  private static final long JWT_EXPIRATION_TIME = 864000000; // 10 days

  @Override
  public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
    Authentication authentication) throws IOException, ServletException {
    String username = authentication.getName();

    String token = Jwts.builder()
      .setSubject(username)
      .setExpiration(new Date(System.currentTimeMillis() + JWT_EXPIRATION_TIME))
      .signWith(SignatureAlgorithm.HS512, JWT_SECRET.getBytes())
      .compact();

    response.setHeader("Authorization", "Bearer " + token);
    response.getWriter().write("{\"token\":\"Bearer " + token + "\"}");
    response.setContentType("application/json");
  }

}

在上述代码中,我们使用了JJWT库来生成JWT。在onAuthenticationSuccess方法中,我们首先从Authentication对象获取用户名,然后使用用户名创建JWT。我们设置JWT的有效期为10天,并使用HS512签名算法对JWT进行签名,使用一个字符串作为密钥。最后,我们将JWT作为Bearer令牌添加到响应消息头中,并封装在JSON格式的响应体中返回给客户端。

public class JWTAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

  @Override
  public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
    AuthenticationException exception) throws IOException, ServletException {
    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    response.getWriter().write("{\"error\":\"Bad credentials\"}");
    response.setContentType("application/json");
  }

}

在上述代码中,我们将响应代码设置为401(未经授权),并向响应体中添加一个错误消息,以通知客户端身份验证失败。

实现授权控制器

现在我们已经创建了认证应用程序的基本安全性,让我们来构建资源应用程序并实现授权控制器,以确保只有经过身份验证的用户才可以访问受保护的资源。我们将使用JWT来验证用户身份。

@RestController
public class ResourceController {

  private static final String JWT_SECRET = "secret";

  @GetMapping("/resource")
  public ResponseEntity<String> getResource(HttpServletRequest request) {
    String token = request.getHeader("Authorization").replace("Bearer ", "");
    if (isValidJWT(token)) {
      return ResponseEntity.ok("Protected resource");
    } else {
      return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
    }
  }

  private boolean isValidJWT(String jwt) {
    try {
      Jwts.parser().setSigningKey(JWT_SECRET.getBytes()).parseClaimsJws(jwt);
      return true;
    } catch (JwtException e) {
      return false;
    }
  }

}

在上述代码中,我们使用了一个示例的受保护资源路径"/resource",该路径只允许经过身份验证的用户访问。我们从请求头中提取Bearer令牌,并使用isValidJWT方法验证令牌的真实性。如果JWT有效,则返回200响应代码和受保护的资源;否则返回401(未经授权)响应代码。

资源应用程序

现在我们已经创建了认证应用程序,让我们来创建一个资源应用程序,以便用户可以在验证后访问它。资源应用程序将验证用户是否具有访问受保护资源的权限。

配置Spring Security

我们首先需要配置Spring Security,以使资源应用程序能够验证JWT并授予用户访问权限。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .csrf().disable()
      .authorizeRequests()
      .antMatchers("/resource").authenticated()
      .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
      .and().addFilterBefore(new JWTAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
  }

}

在上述配置中,我们定义了一个路由表达式"/resource",只有经过身份验证的用户才能访问。我们还将会话管理策略设置为STATELESS,以避免使用HTTP会话。

实现JWTAuthorizationFilter

接下来,我们需要实现JWTAuthorizationFilter,以验证来自客户端的JWT并将其与用户信息相关联。这将允许我们检查用户是否具有访问资源的权限。

public class JWTAuthorizationFilter extends OncePerRequestFilter {

  private static final String JWT_SECRET = "secret";

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
    FilterChain filterChain) throws ServletException, IOException {
    String authorizationHeader = request.getHeader("Authorization");

    if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
      filterChain.doFilter(request, response);
      return;
    }

    String jwt = authorizationHeader.replace("Bearer ", "");

    try {
      Jws<Claims> claimsJws = Jwts.parser().setSigningKey(JWT_SECRET.getBytes()).parseClaimsJws(jwt);

      String username = claimsJws.getBody().getSubject();

      List<GrantedAuthority> authorities = new ArrayList<>();
      UserDetails userDetails = new User(username, "", authorities);

      UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
        userDetails, null, userDetails.getAuthorities());

      SecurityContextHolder.getContext().setAuthentication(authentication);
    } catch (JwtException e) {
      throw new ServletException("Invalid JWT");
    }

    filterChain.doFilter(request, response);
  }

}

在上述代码中,我们查询Authorization头以查找Bearer令牌。如果令牌不存在或不正确,则请求将继续传递。否则,我们使用JJWT库验证JWT的真实性,并获取用户的用户名。我们将用户名创建为Spring Security的UserDetails对象并创建一个UsernamePasswordAuthenticationToken,用于将身份验证信息设置为当前Spring Security上下文的一部分。完成后,请求将继续传递并授权用户访问资源。

测试

现在我们已经创建了认证应用程序和资源应用程序,让我们对它们进行测试。首先,我们在认证应用程序上注册并登录,以获取JWT令牌。然后,我们将使用该令牌访问资源应用程序的受保护资源,并验证我们是否可以成功访问。

# Register and login to authentication application
$ curl -s -X POST -H "Content-Type: application/json" -d '{"username":"user","password":"password"}' http://localhost:8080/auth/signup
$ curl -s -X POST -H "Content-Type: application/json" -d '{"username":"user","password":"password"}' http://localhost:8080/auth/login

# Get JWT token
$ TOKEN=$(curl -si -X POST -H "Content-Type: application/json" -d '{"username":"user","password":"password"}' http://localhost:8080/auth/login | grep 'Authorization:' | awk '{print $2}')

# Access protected resource in resource application
$ curl -s -H "Authorization: Bearer $TOKEN" http://localhost:8090/resource
Protected resource

通过测试,我们可以看到我们成功地访问了资源应用程序的受保护资源,并返回了正确的响应。

总结

在本文中,我们使用Spring Boot,Spring Security和JWT实现了一个基本的单点登录系统。我们介绍了JWT的概念,并演示了如何使用它来验证用户身份。我们还创建了一个认证应用程序和一个资源应用程序,以演示如何在多个应用程序之间共享用户身份验证信息。您可以将此范例用作基础模板,进一步扩展它以适应自己的应用程序需求。文章来源地址https://www.toymoban.com/news/detail-465328.html

到了这里,关于Spring Boot单点登录实践的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【实践篇】基于CAS的单点登录实践之路

    作者:京东物流 赵勇萍 上个月我负责的系统SSO升级,对接京东ERP系统,这也让我想起了之前我做过一个单点登录的项目。想来单点登录有很多实现方案,不过最主流的还是基于CAS的方案,所以我也就分享一下我的CAS实践之路。 单点登录的英文名叫做:Single Sign On(简称SSO)

    2023年04月13日
    浏览(56)
  • JWT 单点登录探析:原理、用途与安全实践

    JWT (JSON Web Token) 是目前最流行的跨域认证解决方案,是 一种基于 Token 的认证授权机制 。 从 JWT 的全称可以看出,JWT 本身也是 Token,一种规范化之后的 JSON 结构的 Token。 通过数字签名的方式,以 JSON 对象为载体,在不同的服务终端之间安全的传输信息。 JWT 自身包含了身

    2024年02月03日
    浏览(30)
  • Java实现单点登录(SSO)详解:从理论到实践

    ✨✨谢谢大家捧场,祝屏幕前的小伙伴们每天都有好运相伴左右,一定要天天开心哦!✨✨  🎈🎈作者主页: 喔的嘛呀🎈🎈 ✨✨ 帅哥美女们,我们共同加油!一起进步!✨✨  目录 引言 一、什么是单点登录(SSO)? 二、SSO的工作原理 三、SSO的具体实现 SSO的核心概念

    2024年04月16日
    浏览(55)
  • 从零开始学Spring Boot系列-前言

    在数字化和信息化的时代,Java作为一种成熟、稳定且广泛应用的编程语言,已经成为构建企业级应用的首选。而在Java生态系统中,Spring框架无疑是其中最为耀眼的一颗明星。它提供了全面的编程和配置模型,用于构建企业级应用。随着Spring Boot的出现,这一框架变得更加易于

    2024年02月22日
    浏览(46)
  • 【论坛java项目】第二章 Spring Boot实践,开发社区登录模块:发送邮件、开发注册功能、会话管理、生成验证码、开发登录、退出功能、

    😀如果对你有帮助的话😊 🌺为博主点个赞吧 👍 👍点赞是对博主最大的鼓励😋 💓爱心发射~💓 bofryuzursekbiab——密码 访问邮箱域名 邮箱端口 账号 密码 协议 详细配置 JavaMailSender 是 Spring Email 的核心组件,负责发送邮件 MimeMessage 用于封装邮件的相关信息 MimeMessageHelper 用

    2024年02月06日
    浏览(42)
  • 深入理解SSO原理,项目实践使用一个优秀开源单点登录项目(附源码)

    深入理解SSO原理,项目实践使用一个优秀开源单点登录项目(附源码)。 一、简介 单点登录(Single Sign On),简称为 SSO。 它的解释是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。 ❝ 所谓一次登录,处处登录。同样一处退出,处处退出。 ❞

    2024年02月11日
    浏览(33)
  • spring security单点登录跳过密码验证

    第一种方案:通过框架密码验证 考虑去掉BCryptPasswordEncoder的配置,直接明文校验, 配置CustomPasswordEncoder 在单点登录验证方法中,先使用用户名查询到数据库中存储的全部用户信息,使查询出来的密码和框架自动调用查询方法得到的数据库密码通过CustomPasswordEncoder matches校验

    2024年02月02日
    浏览(33)
  • Java开发 - 单点登录初体验(Spring Security + JWT)

    目录 ​​​​​​​ 前言 为什么要登录 登录的种类 Cookie-Session Cookie-Session-local storage JWT令牌 几种登陆总结  用户身份认证与授权 创建工程 添加依赖 启动项目 Bcrypt算法的工具 创建VO模型类 创建接口文件 创建XML文件 补充配置 添加依赖 添加配置 创建配置类 测试上面的配置

    2024年02月02日
    浏览(35)
  • 【Spring Boot】Spring Boot自动加载机制:简化应用程序的启动

    在微服务盛行的今天,快速搭建和启动应用程序变得至关重要。Spring Boot作为Java生态系统中主流的框架,其自动加载机制使得开发者能够快速构建和启动应用程序。本文将详细介绍Spring Boot的自动加载机制,并通过代码示例加以说明。 首先,我们要了解Spring Boot自动加载机制

    2024年02月11日
    浏览(27)
  • Spring Boot与Kubernetes:现代云部署的完美组合

    🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页 ——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文并茂🦖生动形象🐅简单易学!欢迎大家来踩踩~🌺 🌊 《IDEA开发秘籍专栏》 🐾 学会IDEA常用操作,工作效率翻倍~💐 🌊 《100天精通Golang(基础

    2024年02月09日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包