Spring boot 成功登录(JWT令牌)后,我的VueJS应用程序调用POST API调用(后端SpringBoot)-获取CORS共享错误PreflightInvalidStatus
我是VueJS的新手。在我的本地工作区中,前端应用程序是使用Vue.js框架(VS代码IDE)开发的。后端使用Java/SpringBoot和基于JWT的登录身份验证(STS IDE)。登录后,我正在使用localStorage保存JWT。之后,HelloWorld.vue组件包含4个按钮-创建包、更新碳、更新账单帐户和更新收款状态。现在,单击createpackage会显示一个新组件,它有一个带有两个简单输入文本框的表单。提交时,有一个POST API调用,JWT令牌通过授权正确发送:“承载者”+令牌。但是获取CORS共享错误:PreflightInvalidStatus 我看到了一些与此相关的线程,但无法得到确切的解决方案。我正在复制UI和后端文件内容。请让我知道当前代码有什么问题,或者需要在UI或后端进行哪些额外配置。提前谢谢 前端代码: App.vueSpring boot 成功登录(JWT令牌)后,我的VueJS应用程序调用POST API调用(后端SpringBoot)-获取CORS共享错误PreflightInvalidStatus,spring-boot,vue.js,axios,jwt,cors,Spring Boot,Vue.js,Axios,Jwt,Cors,我是VueJS的新手。在我的本地工作区中,前端应用程序是使用Vue.js框架(VS代码IDE)开发的。后端使用Java/SpringBoot和基于JWT的登录身份验证(STS IDE)。登录后,我正在使用localStorage保存JWT。之后,HelloWorld.vue组件包含4个按钮-创建包、更新碳、更新账单帐户和更新收款状态。现在,单击createpackage会显示一个新组件,它有一个带有两个简单输入文本框的表单。提交时,有一个POST API调用,JWT令牌通过授权正确发送:“承载者
<template>
<div id="app">
<Nav/>
<router-view/>
</div>
</template>
<script>
import Nav from './components/Nav.vue'
export default {
name: 'App',
components: {
Nav
},
data() {
return {
form: {
username: "",
password: "",
},
showError: false
};
}
};
</script>
<style>
@import url('htpp://fonts.googleapis.com/css?family=Fira+Sans:400,500,600,700,800');
* {
box-sizing:border-box;
}
body{
background: #1C8EF9 !important;
}
body, html,#app, #root, .auth-wrapper{
width :100%;
height:100%;
padding-top:30px;
}
#app{
text-align:center;
}
.navbar-light{
background-color: #ffffff;
box-shadow:0px 14px 80px rgba (34,35,58,0.2);
}
.custom-control-label{
font-weight:100;
}
.forgot-password,
.forgot-password a{
text-align : right;
font-size : 13px;
padding-top:10px;
color:#7f7d7d;
margin:0;
}
.forgot-password a{
color:#167bff;
}
</style>
<template>
<nav class="navbar navbar-expand navbar-light fixed-top">
<div class="container">
<router-link to="/" class="navbar-brand"> Test Data Generator </router-link>
<div class="collapse navbar-collapse">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<router-link to="/login" class="nav-link"> Login </router-link>
</li>
<li class="nav-item">
<router-link to="/login" class="nav-link"> Sign Up </router-link>
</li>
</ul>
</div>
</div>
</nav>
</template>
<script>
export default {
name:'Nav'
}
</script>
<template>
<h3> Hello </h3>
</template>
<script>
export default {
data(){
return{
user:null
}
}
}
</script>
<template>
<div class="auth-wrapper">
<div class="auth-inner">
<form @submit.prevent="handleLogin">
<h3>Login</h3>
<div class="form-group">
<label>Username</label>
<input type="text" class="form-control" v-model="username" placeholder="Username">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" v-model="password" placeholder="Password">
</div>
<button class="btn btn-primary btn-block">Login</button>
</form>
</div>
</div>
</template>
<script>
import axios from 'axios'
import { apiHost } from '../config'
export default {
name:'Login',
data(){
return{
username:'',
password:''
}
},
methods:{
async handleLogin(){
const loginURL=apiHost+'authenticate';
const response = await axios.post(loginURL,{
username:this.username,
password: this.password
});
console.log(response);
localStorage.setItem('token',response.data.jwt);
this.$router.push('/hello');
}
}
}
</script>
<style>
.auth-wrapper{
display:flex;
justify-content:center;
flex-direction:column;
text-align:left;
}
.auth-inner{
width:450px;
margin :auto;
background: #ffffff;
box-shadow:0px 14px 80px rgba (34,35,58,0.2);
padding:40px 55px 45px 55px;
border-radius:15px;
transition: all .3s;
}
.auth-wrapper .form-control:focus{
border-color:#167bff;
box-shadow:none;
}
.auth-wrapper h3{
text-align:center;
margin:0;
line-height:1;
padding-bottom:20px;
}
</style>
<template>
<br><br> <br><br>
<button @click="goToCreate" style='margin-right:16px'> Create Package </button>
<button @click="goToUpdateCarbon" style='margin-right:16px'> Update Carbon </button>
<button @click="goToUpdateBillingAccount" style='margin-right:16px'> Update Billing Account </button>
<button @click="goToUpdateCollectionStatus" style='margin-right:16px'> Update Collection Status </button>
<br><br>
<router-view/>
</template>
<script>
export default {
components: {
},
methods:{
goToCreate:function(){
this.$router.push('/createpackage');
},
goToUpdateCarbon:function(){
this.$router.push('/updatecarbon');
},
goToUpdateBillingAccount:function(){
this.$router.push('/updateBillingAccount');
},
goToUpdateCollectionStatus:function(){
this.$router.push('/updateCollectionStatus');
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
</style>
<template>
<div class="auth-inner">
<form name="createPackageForm" @submit="submitNewPackage" method="post">
<div class="form-group">
<input type="number" name="noOfPostpaid"
placeholder="PostPaid" class="form-control" v-model="posts.noOfPostpaid"
> </div>
<br>
<input type="number" class="form-control" name="noOfPrepaid" placeholder="PrePaid" v-model="posts.noOfPrepaid"
>
<br>
<button>Submit</button>
</form>
</div>
<div >
<br> <br> <br>
<table style="border:1px solid black;margin-left:auto;margin-right:auto;" >
<thead>
<tr>
<th style=" text-align:left;" > Package ID </th>
<th style=" text-align:left;" > PackageType </th>
</tr>
</thead>
<tbody>
<tr v-for="(user) in posts.responseJSON" :key="user.packageId">
<td style=" height: 5px; vertical-align: bottom; " >{{ user.packageId }}</td>
<td style=" height: 5px; vertical-align: bottom; ">{{ user.packageType }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import { apiHost} from '../config'
import axios from 'axios'
export default {
name:"CreatePackage",
data(){
return{
posts: {
noOfPostpaid:null,
noOfPrepaid:null,
responseJSON:[],
}
}
},
methods:{
submitNewPackage(e){
console.warn(apiHost+'tdg/createpackage/'+this.posts.noOfPostpaid+'/'+this.posts.noOfPrepaid);
e.preventDefault();
axios.post(apiHost+'tdg/createpackage/'+this.posts.noOfPostpaid+'/'+this.posts.noOfPrepaid,{
headers: {
'Authorization': 'Bearer '+ localStorage.getItem('token'),
'Access-Control-Allow-Origin':"*",
}},null)
.then(response=>this.posts.responseJSON=response.data)
.catch(e => {
console.log(e);
})
this.posts.noOfPostpaid='';
this.posts.noOfPrepaid='';
}
}
}
</script>
<style >
.form-control:focus{
border-color:#167bff;
box-shadow:none;
}
.auth-inner{
width:450px;
margin :auto;
background: #ffffff;
box-shadow:0px 14px 80px rgba (34,35,58,0.2);
padding:40px 55px 45px 55px;
border-radius:15px;
transition: all .3s;
}
</style>
main.js
let baseUrl = ''
if (process.env.NODE_ENV === 'production') {
baseUrl = 'http://yourdomain.com/api/'
}
else {
baseUrl = 'http://localhost:9000/'
}
export const apiHost = baseUrl
import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import App from './App.vue'
import Login from './components/Login.vue'
import Home from './components/Home.vue'
import HelloWorld from './components/HelloWorld.vue'
import CreatePackage from './components/CreatePackage.vue'
import SearchAndUpdateCarbon from './components/SearchAndUpdateCarbon.vue'
import SearchAndUpdateBillingAccount from './components/SearchAndUpdateBillingAccount.vue'
import SearchAndUpdateCollectionStatus from './components/SearchAndUpdateCollectionStatus.vue'
const router = createRouter({
history: createWebHistory(),
routes:[
{
path : '/login',
component:Login
},
{
path : '/',
component:Home
},
{
path : '/hello',
component:HelloWorld
},
{
path : '/createpackage',
component:CreatePackage
},{
path : '/updatecarbon',
component:SearchAndUpdateCarbon
},
{
path : '/updateBillingAccount',
component:SearchAndUpdateBillingAccount
},
{
path : '/updateCollectionStatus',
component:SearchAndUpdateCollectionStatus
}
]
})
const app= createApp(App);
app.use(router).mount('#app')
后端文件包括:
WebSecurityConfig.java
@EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService myUserDetailsService;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService);
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
.authorizeRequests().antMatchers("/authenticate").permitAll().
anyRequest().authenticated().and().
exceptionHandling().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration().applyPermitDefaultValues();
source.registerCorsConfiguration("/**", corsConfiguration);
return source;
}
}
@CrossOrigin(origins="*")
@RestController
@RequestMapping("/tdg")
public class PackageController {
@PostMapping(path = "/createpackage/{noOfPostpaid}/{noOfPrepaid}")
public ResponseEntity<List<PackageResponse>> createPackageDetails(@PathVariable String noOfPostpaid,
@PathVariable String noOfPrepaid) {
...
HttpStatus status = HttpStatus.OK;
return new ResponseEntity<List<PackageResponse>>(packageResponsesList, status);
}
PackageController.java
@EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService myUserDetailsService;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService);
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
.authorizeRequests().antMatchers("/authenticate").permitAll().
anyRequest().authenticated().and().
exceptionHandling().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration().applyPermitDefaultValues();
source.registerCorsConfiguration("/**", corsConfiguration);
return source;
}
}
@CrossOrigin(origins="*")
@RestController
@RequestMapping("/tdg")
public class PackageController {
@PostMapping(path = "/createpackage/{noOfPostpaid}/{noOfPrepaid}")
public ResponseEntity<List<PackageResponse>> createPackageDetails(@PathVariable String noOfPostpaid,
@PathVariable String noOfPrepaid) {
...
HttpStatus status = HttpStatus.OK;
return new ResponseEntity<List<PackageResponse>>(packageResponsesList, status);
}
@CrossOrigin(origins=“*”)
@RestController
@请求映射(“/tdg”)
公共类包控制器{
@PostMapping(path=“/createpackage/{noofpostpayed}/{noofprayed}”)
public ResponseEntity createPackageDetails(@PathVariable String noOfPostpaid,
@路径变量字符串(0){
...
HttpStatus status=HttpStatus.OK;
返回新的响应属性(PackageResponseList,状态);
}
不确定我的问题为什么被否决。我觉得问题和要求很清楚。请在此处提供解决方案。