Sping Security前后端分离两种实战方案

yizhihongxing

下面我将详细讲解“Sping Security前后端分离两种实战方案”的完整攻略。

方案概述

Spring Security作为一个强大的安全框架,在项目中得到了广泛的应用,但是其安全配置可能会随着项目的复杂度而变得非常繁琐。而前后端分离的架构模式也越来越多地被应用在实际项目中,那么如何在Spring Security中实现前后端分离呢?本文将介绍两种前后端分离的实战方案。

方案一:基于JWT的前后端分离

准备工作

在开始前,需要先明确一下如何在Spring Security中使用JWT:

  1. 引入依赖:

xml
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>

  1. 实现JWT工具类:

```java
public class JwtUtil {

   private static final String SECRET = "mySecret";

   public static String generateToken(UserDetails userDetails) {
       Date now = new Date();
       Date expiryDate = new Date(now.getTime() + 3600000);
       return Jwts.builder()
               .setSubject(userDetails.getUsername())
               .setIssuedAt(now)
               .setExpiration(expiryDate)
               .signWith(SignatureAlgorithm.HS512, SECRET)
               .compact();
   }

   public static String getUsernameFromToken(String token) {
       return Jwts.parser()
               .setSigningKey(SECRET)
               .parseClaimsJws(token)
               .getBody()
               .getSubject();
   }

   public static boolean validateToken(String token, UserDetails userDetails) {
       String username = getUsernameFromToken(token);
       return username.equals(userDetails.getUsername());
   }

}
```

其中,SECRET是自己定义的密钥,在实际项目中需要更改。

方案实现

在基于JWT的前后端分离中,需要实现如下步骤:

  1. 用户登录时,前端发送POST请求,携带用户名和密码。

javascript
axios.post('/login', {
username: this.username,
password: this.password
}).then(response => {
const token = response.data.token;
localStorage.setItem('token', token);
// ...
});

  1. 后端接收请求,进行登录验证,验证成功则生成JWT并作为响应返回给前端。

```java
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

   @Override
   public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
       try {
           AuthenticationRequest authRequest = new ObjectMapper()
                   .readValue(request.getInputStream(), AuthenticationRequest.class);
           UsernamePasswordAuthenticationToken authenticationToken =
                   new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword(), Collections.emptyList());
           return authenticationManager.authenticate(authenticationToken);
       } catch (IOException e) {
           throw new RuntimeException(e);
       }
   }

   @Override
   protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
       UserDetails userDetails = (UserDetails) authResult.getPrincipal();
       String token = JwtUtil.generateToken(userDetails);
       response.addHeader("Authorization", "Bearer " + token);
   }

}
```

其中,AuthenticationRequest是一个POJO,用于接收前端请求中的用户名和密码。

  1. 前端保存JWT,并在每次请求时携带JWT。

javascript
const token = localStorage.getItem('token');
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;

  1. 后端实现JWT的校验,在校验失败时返回401状态码。

```java
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

   @Override
   protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
       String header = request.getHeader("Authorization");
       if (header == null || !header.startsWith("Bearer ")) {
           chain.doFilter(request, response);
           return;
       }
       UsernamePasswordAuthenticationToken authenticationToken = getAuthentication(request);
       SecurityContextHolder.getContext().setAuthentication(authenticationToken);
       chain.doFilter(request, response);
   }

   private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
       String token = request.getHeader("Authorization").replace("Bearer ", "");
       if (JwtUtil.getUsernameFromToken(token) != null) {
           UserDetails userDetails = userDetailsService.loadUserByUsername(JwtUtil.getUsernameFromToken(token));
           if (JwtUtil.validateToken(token, userDetails)) {
               return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
           }
       }
       return null;
   }

}
```

示例一:基于Vue.js的前后端分离

以下是一个基于Vue.js的前后端分离示例,具体实现方式与上述方案实现步骤相同。前端使用了Vue-router进行路由管理,使用了Vue-cookie进行Cookie操作:

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Login from '../views/Login.vue'
import axios from 'axios'
import VueCookies from 'vue-cookies'

Vue.use(VueRouter)
Vue.use(VueCookies)

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/login',
    name: 'Login',
    component: Login
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

router.beforeEach(function (to, from, next) {
  const token = Vue.$cookies.get('token');
  if (to.name !== 'Login' && !token) {
    next({ name: 'Login' });
  } else {
    next();
  }
});

axios.interceptors.request.use(function (config) {
  const token = Vue.$cookies.get('token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

export default router

示例二:基于React的前后端分离

以下是一个基于React的前后端分离示例,具体实现方式与上述方案实现步骤相同。前端使用了React-router进行路由管理,使用了Js-cookie进行Cookie操作:

import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import Cookie from 'js-cookie';

function PrivateRoute({ component: Component, ...rest }) {
  return (
    <Route
      {...rest}
      render={props =>
        Cookie.get('token') ? (
          <Component {...props} />
        ) : (
          <Redirect
            to={{
              pathname: '/login',
              state: { from: props.location }
            }}
          />
        )
      }
    />
  );
}

export default PrivateRoute;

方案二:基于Session的前后端分离

准备工作

在开始前,需要先明确一下如何在Spring Security中使用Session:

  1. 引入依赖:

xml
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-core</artifactId>
<version>1.3.3.RELEASE</version>
</dependency>

  1. 配置Spring Session,使用Redis作为Session存储:

```java
@Configuration
@EnableRedisHttpSession
public class HttpSessionConfig {

   @Bean
   public LettuceConnectionFactory connectionFactory() {
       return new LettuceConnectionFactory();
   }

}
```

方案实现

在基于Session的前后端分离中,需要实现如下步骤:

  1. 用户登录成功后,后端生成Session,并返回JSESSIONID给前端。

```java
public class SessionAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

   @Override
   public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
       HttpSession session = request.getSession();
       session.setAttribute("user", authentication.getPrincipal());
       response.getWriter().write(session.getId());
   }

}
```

  1. 前端保存JSESSIONID,并在每次请求时携带JSESSIONID。

javascript
const sessionId = localStorage.getItem('sessionId');
axios.defaults.headers.common['Cookie'] = `JSESSIONID=${sessionId}`;

  1. 后端根据JSESSIONID查找Session,并进行验证,验证成功则放行请求。

```java
public class SessionFilter extends GenericFilterBean {

   private final SessionRegistry sessionRegistry;

   public SessionFilter(SessionRegistry sessionRegistry) {
       this.sessionRegistry = sessionRegistry;
   }

   @Override
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
       if (request instanceof HttpServletRequest) {
           HttpSession session = ((HttpServletRequest) request).getSession(false);
           if (session != null) {
               UserDetails userDetails = (UserDetails) session.getAttribute("user");
               if (userDetails != null) {
                   SessionInformation sessionInformation = sessionRegistry.getSessionInformation(session.getId());
                   if (sessionInformation != null) {
                       if (sessionInformation.isExpired()) {
                           sessionRegistry.removeSessionInformation(session.getId());
                       } else {
                           SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()));
                       }
                   }
               }
           }
       }
       chain.doFilter(request, response);
   }

}
```

示例三:基于Angular的前后端分离

以下是一个基于Angular的前后端分离示例,具体实现方式与上述方案实现步骤相同。前端使用了Angular Router进行路由管理,使用了ngx-cookie-service进行Cookie操作:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LoginComponent } from './login/login.component';
import { HomeComponent } from './home/home.component';
import { AuthGuard } from './auth.guard';
import { CookieService } from 'ngx-cookie-service';

const routes: Routes = [
  { path: 'login', component: LoginComponent },
  { path: '', component: HomeComponent, canActivate: [AuthGuard] }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {
  constructor(private cookieService: CookieService) {
    const sessionId = this.cookieService.get('JSESSIONID');
    document.cookie = 'JSESSIONID=' + sessionId;
  }
}

总结

本文介绍了两种基于Spring Security的前后端分离实现方案,基于JWT和基于Session。在使用前后端分离的架构模式时,只需要根据具体的项目需要选择合适的方案进行实现即可。在实际项目中,需要注意安全性和稳定性,并且需要注重实际应用效果的测试,以保证系统的稳定性和安全性。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Sping Security前后端分离两种实战方案 - Python技术站

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

相关文章

  • java调用chatgpt接口来实现专属于自己的人工智能助手

    让我来详细讲解一下“java调用chatgpt接口来实现专属于自己的人工智能助手”的攻略。 1. 确定chatgpt的API接口 要使用chatgpt接口,我们需要先确定其API接口地址和请求方式。一般来说,这些信息可以在chatgpt的官方文档中找到。 以chatgpt的官方文档为例,我们可以在这里看到它的API接口地址和请求方式:https://chat…

    Java 2023年5月26日
    00
  • 基于Listener监听器生命周期(详解)

    基于Listener监听器生命周期(详解) 在Java Web应用中,我们可以通过监听器(Listener)来监听 Web应用中的事件,如ServletContext的创建与销毁、HttpSession的创建与销毁、ServletRequest的创建与销毁等等。本文将详细介绍Listener的生命周期。 1. Listener简介和分类 Listener(监…

    Java 2023年6月15日
    00
  • IDEA反编译出整个jar包源码

    你好,关于“IDEA反编译出整个jar包源码”的完整攻略,我可以提供以下几个步骤: 步骤一:安装插件 首先,你需要在 IDEA 中安装一个名为 “JD-Eclipse”的插件。这个插件可以在 IDEA 中实现反编译的功能。安装插件可以按照 IDEA 的标准步骤进行,在 IDEA 的插件中心选择安装即可。 步骤二:打开jar包 打开 IDEA,选择 “File…

    Java 2023年5月26日
    00
  • Java maven三种仓库,本地仓库,私服,中央仓库的配置

    Java maven作为代表性的构建工具,具有良好的依赖管理、插件扩展等特性。它的运行需要依赖于仓库的配置,而常见的仓库包括本地仓库、私服、中央仓库。下面将分别对这三种仓库进行详细的配置攻略。 本地仓库配置 1.在本地磁盘上创建一个文件夹作为本地仓库。例如:C:\Users\UserName.m2\repository 2.在maven的全局配置文件中(se…

    Java 2023年5月20日
    00
  • Spring Security 基于URL的权限判断源码解析

    下面我来详细讲解“Spring Security 基于URL的权限判断源码解析”的完整攻略。 1. 前置知识准备 在深入了解 Spring Security 基于 URL 权限判断的源码之前,我们需要先对以下概念有所了解: 身份验证(Authentication):验证用户的身份,通常需要用户提供用户名和密码等身份凭证。 授权(Authorization):…

    Java 2023年6月3日
    00
  • eclipse下整合springboot和mybatis的方法步骤

    下面是整合Spring Boot和Mybatis的方法步骤: 准备工作 安装Eclipse IDE,确保你已经安装了Eclipse插件“Spring Tools 4”,这个插件可以大大简化整合的过程。 创建一个基于Maven的Spring Boot项目,在pom.xml文件中添加如下依赖项: <dependencies> <!– Spri…

    Java 2023年5月20日
    00
  • js+css实现的简单易用兼容好的分页

    这里是“js+css实现的简单易用兼容好的分页”的完整攻略: 什么是分页 分页指的是将大量数据分成多个页面,每次只显示其中的一部分数据,通过点击下一页或上一页来切换页面。常见的应用包括商城商品列表、新闻列表等。 分页的实现 HTML 首先,我们需要在HTML页面中添加分页的DOM结构。一般来说,分页的结构包含上一页、下一页、页码数等元素。 <div c…

    Java 2023年6月16日
    00
  • 快速学习JavaWeb中监听器(Listener)的使用方法

    我将为您详细讲解快速学习JavaWeb中监听器的使用方法。 一、什么是监听器 在 JavaWeb 中,监听器(Listener)是一种特殊的对象,能够监听 Web 应用程序运行时所发生的事件,并对这些事件作出相应的反应。 二、监听器的使用方法 1. 编写监听器类 监听器作为一个独立的 Java 类,需要实现对应的监听器接口。在 JavaWeb 中,常用的监听…

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