SpringSecurity实现前后端分离的示例详解

为了讲解本文的主题,我们需要先了解以下几个概念:

  1. 前后端分离:前后端分离是指将前端和后端业务逻辑分开,前端主要负责展示数据和交互逻辑,后端主要负责提供API接口和业务逻辑。
  2. Spring Security:Spring Security是基于Spring框架的安全框架,主要提供身份认证、授权、攻击防护等安全功能。
  3. Token认证:Token认证是一种基于Token的认证方式,服务器在认证成功后返回给客户端一个Token,客户端在请求接口时需要将Token带上,服务器根据Token来判断客户端的身份。

接下来,我们将讲解如何使用Spring Security实现前后端分离的示例。

一、前端实现Token认证

前端实现Token认证的目的是为了在用户成功登录后,获取Token并将其保存在本地,然后在访问需要认证的API接口时将Token带上。这里我们使用Vue.js作为前端框架,使用Axios作为http库,示例代码如下:

import axios from 'axios';

// 设置Token
function setToken(token) {
  localStorage.setItem('Token', token);
}

// 获取Token
function getToken() {
  return localStorage.getItem('Token');
}

// 在请求头中添加Token
axios.interceptors.request.use(function(config) {
  const token = getToken();
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

// 登录
export function login(username, password) {
  return axios.post('/api/login', {
    username,
    password,
  }).then(response => {
    const token = response.data.token;
    setToken(token);
    return response;
  });
}

如上代码中,我们使用localStorage保存Token,在请求头中添加Token。当用户成功登录后,我们调用login方法,将用户名和密码传给后端验证,验证成功后将Token保存在本地,并返回登录成功的响应结果。

二、后端实现Token认证

后端实现Token认证的主要目的是为了在客户端请求接口时,根据Token判断客户端的身份是否合法,如果合法则返回数据,如果不合法则返回401状态码。这里我们使用Spring Security提供的Token认证方式。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private UserDetailsService userDetailsService;

  @Autowired
  private SecurityProperties securityProperties;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    // 开启跨域
    http.cors().and().csrf().disable();

    // 登录过滤器
    http.addFilterBefore(new JwtAuthenticationFilter(securityProperties), UsernamePasswordAuthenticationFilter.class);

    // 其他请求都需要认证
    http.authorizeRequests().anyRequest().authenticated();
  }

  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
  }

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

}

如上代码中,我们在SecurityConfig类中使用@EnableWebSecurity注解开启Spring Security,并将UserDetailsService注入到configureGlobal方法中,以便为用户提供身份认证功能。另外,我们还通过HttpSecurity对象开启跨域、添加Token认证过滤器并设置其他的请求都需要认证。

具体的Token认证过滤器JwtAuthenticationFilter实现如下:

public class JwtAuthenticationFilter extends OncePerRequestFilter {

  private final SecurityProperties securityProperties;

  public JwtAuthenticationFilter(SecurityProperties securityProperties) {
    this.securityProperties = securityProperties;
  }

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
    String token = getTokenFromRequest(request);

    if (StringUtils.hasText(token) && JwtUtils.validateToken(token, securityProperties.getSecret())) {
      Authentication authentication = JwtUtils.getAuthentication(token);
      SecurityContextHolder.getContext().setAuthentication(authentication);
    } else {
      SecurityContextHolder.getContext().setAuthentication(null);
    }

    chain.doFilter(request, response);
  }

  private String getTokenFromRequest(HttpServletRequest request) {
    String bearerToken = request.getHeader("Authorization");
    if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
      return bearerToken.substring(7);
    }
    return null;
  }

}

如上代码中,我们从request中获取Token并校验,如果校验通过,则将认证信息存入SecurityContextHolder中,如登录名、角色等信息。

三、示例一:请求用户信息

假设我们的系统中,需要获取当前登录用户的信息,我们可以在前端使用Axios在请求时将Token带上,如下:

function getUserInfo() {
  return axios.get('/api/user/info').then(response => {
    const userInfo = response.data.userInfo;
    return userInfo;
  });
}

如上代码中,我们调用getUserInfo方法,Axios会自动将Token带上,并向后端请求用户信息。

然后,在后端我们需要编写一个接口获取当前登录用户的信息,示例代码如下:

@RestController
@RequestMapping("/api/user")
public class UserController {

  @GetMapping("/info")
  @PreAuthorize("hasRole('ADMIN')")
  public Map<String, Object> getUserInfo(Authentication authentication) {
    Map<String, Object> user = new HashMap<>();
    if (authentication != null) {
      user.put("username", authentication.getName());
      user.put("roles", authentication.getAuthorities());
    }
    return Collections.singletonMap("userInfo", user);
  }

}

如上代码中,我们使用@PreAuthorize("hasRole('ADMIN')")注解来设置只有ADMIN角色的用户才可以访问该接口。当请求进来后,Spring Security会根据Token认证客户端的身份,并判断客户端是否具有ADMIN角色,最终根据判断结果返回用户信息或401状态码。

四、示例二:使用Token登录

接下来我们将讲解使用Token登录的示例。用户在登录时输入用户名和密码,后端根据用户名和密码验证成功返回Token,前端将Token保存在本地,在请求API时带上Token。我们在前端添加如下方法用于登录:

export function login(username, password) {
  return axios.post('/api/login', {
    username,
    password,
  }).then(response => {
    const token = response.data.token;
    setToken(token);
    return response;
  });
}

如上代码中,我们使用Axios向后端发送登录请求,如果成功则将返回的Token保存到本地。

接下来,我们需要在后端添加登录接口,示例代码如下:

@RestController
public class LoginController {

  @Autowired
  private AuthenticationManager authenticationManager;

  @Autowired
  private JwtProperties jwtProperties;

  @PostMapping("/api/login")
  public Map<String, Object> login(@RequestBody LoginRequest request) {
    final String username = request.getUsername();
    final String password = request.getPassword();

    Authentication authentication = null;
    try {
      authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
    } catch (BadCredentialsException e) {
      throw new RuntimeException("用户名或密码错误");
    }

    String token = generateJwtToken(authentication);

    return Collections.singletonMap("token", token);
  }

  private String generateJwtToken(Authentication authentication) {
    UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
    return JwtUtils.generateToken(userDetails.getUsername(), jwtProperties.getSecret(), jwtProperties.getExpiration());
  }

}

如上代码中,我们使用@PostMapping("/api/login")注解来设置登录接口,当接收到前端的用户名和密码时,使用AuthenticationManager.authenticate方法对用户名和密码进行验证,如果验证通过则生成一个Token,并将Token返回给前端。

至此,我们已经完成了使用Token实现登录的示例。

五、总结

本文详细讲解了使用Spring Security实现前后端分离的示例,涵盖了前端实现Token认证、后端实现Token认证以及两个示例的完整代码。在实际开发中,我们可以根据这个示例进行扩展,实现更加复杂的业务逻辑。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringSecurity实现前后端分离的示例详解 - Python技术站

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

相关文章

  • 流式图表拒绝增删改查之kafka核心消费逻辑下篇

    首先我们需要了解一下本篇攻略讲解的是什么。 本文的主要内容是讲解如何将Kafka的核心消费逻辑结合流式图表进行可视化呈现,进而达到更好的监控和管理分布式系统的目的。 在具体讲解之前,我们需要明确几个概念: Kafka:一个高吞吐量、分布式的消息队列系统,主要用于解决大数据流的问题。 流式图表:一种可视化数据流的工具,可以通过图形化的方式展示数据流中的数据和流…

    Java 2023年5月20日
    00
  • Maven插件docker-maven-plugin的使用

    下面是关于” Maven插件docker-maven-plugin的使用”的完整攻略,包含了插件的介绍、使用方式和示例。 Maven插件docker-maven-plugin简介 docker-maven-plugin是一款Maven插件,它可以让你使用 Maven 来构建、运行和管理 Docker 镜像。它基于 Docker Java API 和 Dock…

    Java 2023年5月19日
    00
  • 详解Java时区处理之Date,Calendar,TimeZone,SimpleDateFormat

    详解Java时区处理之Date, Calendar, TimeZone, SimpleDateFormat Java中有多种处理日期时间和时区的类,包括Date、Calendar、TimeZone、SimpleDateFormat等。了解这些类的使用方法以及它们之间的区别非常重要。下面我们对这些类逐一进行了解。 Date类 Date是Java中表示日期时间的…

    Java 2023年5月20日
    00
  • java 中JDBC连接数据库代码和步骤详解及实例代码

    下面是详细讲解 “java 中JDBC连接数据库代码和步骤详解及实例代码” 的攻略: JDBC 连接数据库的步骤 在 Java 中,连接数据库需要以下步骤: 加载数据库驱动程序:通过调用 Class.forName() 方法,加载驱动程序。代码示例: Class.forName("com.mysql.jdbc.Driver"); 创建数据…

    Java 2023年5月19日
    00
  • Spring boot应用启动后首次访问很慢的解决方案

    当Spring Boot应用启动后,由于需要初始化一些bean、加载配置文件等,首次访问时可能会比较慢。为了解决这个问题,我们可以采取以下措施: 1. 添加DevTools依赖 Spring Boot提供了DevTools依赖,可以实现热部署和自动重启功能,从而提高开发时的效率。同时,它还能解决首次访问慢的问题。只需要在项目的pom.xml文件中添加如下依赖…

    Java 2023年6月15日
    00
  • Flex与.NET互操作 使用FileReference+HttpHandler实现文件上传/下载

    Flex与.NET互操作 使用FileReference+HttpHandler实现文件上传/下载 概述 本文主要介绍如何通过Flex和.NET相互配合,实现文件上传/下载。 在介绍具体步骤之前,先简单介绍FileReference和HttpHandler。 FileReference是Flex中处理文件上传/下载的类,使用FileReference类可以实…

    Java 2023年6月15日
    00
  • SpringBoot启动流程SpringApplication准备阶段源码分析

    下面就详细讲解一下“SpringBoot启动流程SpringApplication准备阶段源码分析”的完整攻略。SpringBoot启动流程可以分为准备阶段、运行阶段、关闭阶段三个阶段,而本篇主要介绍SpringApplication的准备阶段。 SpringBoot启动流程简介 SpringBoot启动流程包括如下三个阶段: 准备阶段:包括Applicat…

    Java 2023年5月31日
    00
  • 【经典】一位数据挖掘成功人士给数据挖掘在读研究生的建议

    我将为您详细讲解“【经典】一位数据挖掘成功人士给数据挖掘在读研究生的建议”的完整攻略。 1. 文章介绍 该文章通过访问一位成功的数据挖掘专家,分享了一些数据挖掘在读研究生应该具备的知识和技巧,以及在当前数据挖掘领域的趋势和机会。该文章对于正在学习数据挖掘的学生有着重要的参考价值。 2. 数据挖掘研究生的必备技能 在文章中,该数据挖掘专家分享了一些数据挖掘研究…

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