前后端分离,使用vue3整合SpringSecurity加JWT实现登录校验

这篇具有很好参考价值的文章主要介绍了前后端分离,使用vue3整合SpringSecurity加JWT实现登录校验。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前段时间写了一篇spring security的详细入门,但是没有联系实际。

所以这次在真实的项目中来演示一下怎样使用springsecurity来实现我们最常用的登录校验。本次演示使用现在市面上最常见的开发方式,前后端分离开发。前端使用vue3进行构建,用到了element-plus组件库、axios封装、pinia状态管理、Router路由跳转等技术。后端还是spring boot整合springsecurity+JWT来实现登录校验。

本文适合有一定基础的人来看,如果你对springsecurity安全框架还不是很了解,建议你先去看一下我之前写过的spring security框架的快速入门:

springboot3整合SpringSecurity实现登录校验与权限认证(万字超详细讲解)_springboot3 + springsecurity6 校验密码-CSDN博客

技术栈版本:vue3.3.11、springboot3.1.5、spring security6.x

业务流程:

前后端分离,使用vue3整合SpringSecurity加JWT实现登录校验,spring boot整合第三方技术,vue.js,spring boot,securtty

可以看到整个业务的流程还是比较简单的,那么接下来就基于这个业务流程来进行我们具体代码的编写和实现;

前端:

新建一个vue项目,并引入一些具体的依赖;我们本次项目用到的有:element-plus、axios、pinia状态管理、Router路由跳转(注意我们在项目中使用到的pinia要引入持久化插件)

在vue项目中新建两个组件:Login.vue(登录组件,负责登录页面的展示)、Layout.vue(布局页面,负责整体项目的布局,登录成功之后就是跳转到这个页面)

路由的定义:在router文件夹下新建index.ts文件

import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'login',
      component: () => import('@/components/Login.vue')
    },
    {
      path: '/layout',
      name: 'layout',
      component: () => import('@/components/Layout.vue')
    }
  ]
})

export default router

定义Login登录组件为默认的组件,并定义Layout组件;

useToken的状态封装:在stoers文件夹下新建useToken.ts

import { defineStore } from 'pinia'
import { ref } from 'vue'
const useTokenStore = defineStore('token', ()=>{
const token=ref()


const removeToken=()=>{
    token.value=''
}

return {token,removeToken}
},
{persist: true}
)

export default useTokenStore

axios的封装:在utils文件夹在新建request.ts文件

import axios from "axios";
import  useTokenStore from '@/stores/useToken'
import { ElMessage } from 'element-plus';
// 先建一个api
const api = axios.create({
    baseURL: "http://localhost:8888",
    timeout: 5000
});
// 发送请求前拦截
api.interceptors.request.use(
    config =>{
const useToken = useTokenStore();
if(useToken.token){
    console.log("请求头toekn=====>", useToken.token);
    // 设置请求头
    // config.headers['token'] = useToken.token;
    config.headers.token = useToken.token;
}
        return config;

},
error =>{

    return Promise.reject(error);
}
)

// 响应前拦截
api.interceptors.response.use(
    response =>{
        console.log("响应数据", response);
if(response.data.code !=200){
    ElMessage.error(response.data.message);
}

        return response;
},
error =>{
    return Promise.reject(error);
}
)

export default api;

在请求前拦截,主要是为了在请求头中新增token。在request.ts中引入了useToken,并判断如果token不为空,那么在请求头中新增token。

在响应前也进行了一次拦截,如果后端返回的状态码不为200,那么就打印出错误信息;

接下来就可以在Login.vue中进行我们的登录逻辑的具体编写了(我直接将组件内容进行复制了,也不是什么太难的东西,主要还是element-plus的表单):

<template>
    <div class="background" style="font-family:kaiti" >

<!-- 注册表单 -->
<el-dialog v-model="isRegister" title="用户注册" width="30%">
    <el-form label-width="120px" v-model="registerForm">
        <el-form-item label="用户名">
            <el-input type="text"   v-model="registerForm.username"   >
              <template #prefix>
                <el-icon><Avatar /></el-icon>
              </template>
            </el-input>
        </el-form-item>
        <el-form-item label="密码">
            <el-input  type="password" v-model="registerForm.password" >
              <template #prefix>
        <el-icon><Lock /></el-icon>
        </template>
            </el-input>
        </el-form-item>
        <el-form-item>
            <el-button type="primary" @click="registerAdd" >提交</el-button>
            <el-button @click="isRegister = false">取消</el-button>
        </el-form-item>
    </el-form>
</el-dialog>

<!-- 登陆框 -->
<div class="login-box">
<el-form
    label-width="100px"
    :model="loginFrom"
    style="max-width: 460px"
    :rules="Loginrules"
    ref="ruleFormRef"
  >
    <el-form-item label="用户名"  prop="username">
      <el-input v-model="loginFrom.username"  clearable  >
        <template #prefix>
                <el-icon><Avatar /></el-icon>
              </template>
        </el-input>
    </el-form-item>
    <el-form-item label="密码" prop="password">

      <el-input v-model="loginFrom.password"   show-password   clearable  type="password" >
        <template #prefix>
        <el-icon><Lock /></el-icon>
        </template>
      </el-input>
    </el-form-item>

    <el-form-item label="验证码"  prop="codeValue">
      <el-input v-model="loginFrom.codeValue"  style="width: 100px;"  clearable  >
      </el-input>
      <img :src="codeImage" @click="getCode" style="transform: scale(0.9);"/>
    </el-form-item>

    <el-button type="success" @click="getLogin(ruleFormRef)"  style="transform: translateX(50px)"  class="my-button">登录</el-button>
    <el-button type="primary" @click="isRegister=true" class="my-button">注册</el-button>
  </el-form>

</div>

    </div>
</template>

<script lang="ts" setup>
import { ref,onMounted,reactive } from 'vue';
import { useRouter } from 'vue-router';
import { ElMessage } from 'element-plus';
import useTokenStore  from '@/stores/useToken'
import  api  from '@/utils/request'
import type { FormInstance, FormRules } from 'element-plus'
const ruleFormRef =  ref<FormInstance>()

const loginFrom=ref({
username:'',
password:'',
codeKey:'',
codeValue:''
})

const Loginrules=reactive({

  username: [
    { required: true, message: '请输入用户名', trigger: 'blur' }
  ],
  password: [
    { required: true, message: '请输入密码', trigger: 'blur' },
    { min: 6, max: 12, message: '长度在 6 到 12 个字符', trigger: 'blur'}
  ],
  codeValue: [
    { required: true, message: '请输入验证码', trigger: 'blur' }
  ]

})

const registerForm=ref({
  username:'',
  password:''
})

const codeImage=ref('')

const isRegister=ref(false)

const tokenStore = useTokenStore();


const router = useRouter()



const getLogin = async(formEl: FormInstance | undefined) => {

  if (!formEl)  return

  await formEl.validate((valid, fields) => {
    if (valid) {
      console.log('submit!')
      
    } else {
      ElMessage('请输入完整信息')
      return;
    }
  })

  let {data}=await api.post('/user/login',loginFrom.value)

if(data.code==200){
  ElMessage('登录成功')
  console.log(data);
  tokenStore.token=data.data
  router.replace({name:'layout'})
}else{

  ElMessage('登录失败')
}


}


const getCode=async()=>{
  let {data}=await api.get('/getCaptcha')
  loginFrom.value.codeKey=data.data.codeKey
  codeImage.value=data.data.codeValue

}

const registerAdd=async()=>{
let {data}=await api.post('/user/register',registerForm.value)

if(data.code==200){
  ElMessage('注册成功')
  isRegister.value=false
}else{

  ElMessage('注册失败')
  isRegister.value=false
  }

}

// 页面加载完成获取验证码

onMounted(()=>{
getCode()

})


</script>

这个页面中,我还加入了一个图形验证码。还有一个注册的表单。其他的就和普通的登录一样了;

这个页面的最终效果如图:

前后端分离,使用vue3整合SpringSecurity加JWT实现登录校验,spring boot整合第三方技术,vue.js,spring boot,securtty

Layout.vue页面中,我们只进行两个方法的测试;一个是获取当前用户的具体信息,一个是退出登录的按钮;

<template>
    <div class="common-layout">
    <el-container>
          <el-header height="100px">
            头部
            <el-button type="primary" @click="getUserInfo">获取用户信息</el-button>
            <el-button type="success" @click="Logout">退出登录</el-button>
        </el-header>
    
    <el-container>
    <el-aside width="200px">
        菜单栏
    </el-aside>
    <el-main>
        展示区
    </el-main>
    </el-container>
    </el-container>
  </div>


</template>

<script lang="ts" setup name="Layout">
import { ref } from 'vue'
import api from '@/utils/request'
import {ElMessage} from 'element-plus'
import { useRouter } from 'vue-router'
import  useToeknStore from '@/stores/useToken'
const router = useRouter()

const Logout =async () => {
 let data= api.get("/user/logout")
if(data.data.code==200){
ElMessage.success('退出成功')
// 清除token
useToeknStore().removeToken
router.replace({name:'login'})
}
else{
  ElMessage.error('退出失败')
}

}

const getUserInfo = async() => {

let data=await api.get("/user/info")

console.log('@',data);

}


</script>

数据库:

我新建一个数据表,用于登录校验:

CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(255) NOT NULL,
    password VARCHAR(255) NOT NULL,
    expired BOOLEAN NOT NULL
);

这张表中只有简单的用户名,密码,和用户是否过期等字段;

后端:  

新建一个spring boot项目,并导入以下的依赖:

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

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>


        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>4.3.0</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3.1</version>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.18</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.21</version>
        </dependency>

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

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


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

后端使用MybatisPlus做用户的增、删、改、查等。基础的controller、service、mapper,我就不再这里进行赘述了;

新建一个类MyTUserDetail ,继承UserDetail:

@Data
public class MyTUserDetail implements Serializable , UserDetails {

    private static final long serialVersionUID = 1L;

private User User;

@JsonIgnore  //json忽略
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
 
        return null;
    }
 
 
    @JsonIgnore
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    @JsonIgnore
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
    @JsonIgnore
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
    @JsonIgnore
    @Override
    public boolean isEnabled() {
        return true;
    }
}

新建一个类MyUserDetailServerImpl,实现MyUserDetailServer接口的loadUserByUsername方法

@Service
public class MyUserDetailServerImpl implements MyUserDetailServer {
    @Autowired
    UserMapper userService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User tUser = userService.selectOne(new LambdaQueryWrapper<User>().
                eq(username != null, TUser::getUsername, username));
        if (tUser == null) {
            throw new UsernameNotFoundException("用户名不存在");
        }

        MyTUserDetail myTUserDetail=new MyTUserDetail();
myTUserDetail.setTUser(tUser);
        return myTUserDetail;
    }
}

新建一个JwtUtils的工具类,来生成token;

@Component
public class JwtUtil {

    private final String secret="zhangqiao";

    private final Long expiration=36000000L;

    public String generateToken(Integer id) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + expiration);

        Algorithm algorithm = Algorithm.HMAC256(secret);
        return JWT.create()
                .withSubject(String.valueOf(id))
                .withIssuedAt(now)
                .withExpiresAt(expiryDate)
                .sign(algorithm);
    }

    public Integer getUsernameFromToken(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return Integer.valueOf(jwt.getSubject());
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /*
    * 判断token是否过期
    * */
    public boolean isTokenValid(String token) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWT.require(algorithm).build().verify(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /*
    * 刷新token
    * */

    public String refreshToken(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            String username = jwt.getSubject();
            Algorithm algorithm = Algorithm.HMAC256(secret);

            Date now = new Date();
            Date expiryDate = new Date(now.getTime() + expiration);

            return JWT.create()
                    .withSubject(username)
                    .withIssuedAt(now)
                    .withExpiresAt(expiryDate)
                    .sign(algorithm);
        } catch (JWTDecodeException e) {
            return null;
        }
    }
}

新建一个Jwt的拦截类,继承一个OncePerRequestFilter类,用来在每次请求前拦截请求,并从中获取token,并判断这个token是否是我们用户表中的token;

如果是,那么将用户信息存储到security中,这样后面的过滤器就可以获取到用户信息了,如果不是,那么直接放行。我们会将这个拦截器加入到UsernamePasswordAuthenticationFilter过滤器之前。

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //获取请求头中的token
        String token = request.getHeader("token");
        System.out.println("前端的token信息=======>"+token);
        //如果token为空直接放行,由于用户信息没有存放在SecurityContextHolder.getContext()中所以后面的过滤器依旧认证失败符合要求
        if(!StringUtils.hasText(token)){
            filterChain.doFilter(request,response);
            return;
        }

//        解析Jwt中的用户id
        Integer userId = jwtUtil.getUsernameFromToken(token);
        //从redis中获取用户信息
        String redisUser = redisTemplate.opsForValue().get(String.valueOf(userId));
        if(!StringUtils.hasText(redisUser)){
            filterChain.doFilter(request,response);
            return;
        }

        MyTUserDetail myTUserDetail= JSON.parseObject(redisUser, MyTUserDetail.class);

        //将用户信息存放在SecurityContextHolder.getContext(),后面的过滤器就可以获得用户信息了。这表明当前这个用户是登录过的,后续的拦截器就不用再拦截了
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken=new UsernamePasswordAuthenticationToken(myTUserDetail,null,null);
        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        filterChain.doFilter(request,response);
    }
}

security配置类的设置:

@Configuration
@EnableWebSecurity
public class MyServiceConfig {

    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    /*
    * security的过滤器链
    * */
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http)throws Exception {
http.csrf(AbstractHttpConfigurer::disable);

http.authorizeHttpRequests((auth) ->
    auth
            .requestMatchers("/getCaptcha","user/login","user/register").permitAll()
            .anyRequest().authenticated()
);
http.cors(cors->{
    cors.configurationSource(corsConfigurationSource());
        });
//自定义过滤器放在UsernamePasswordAuthenticationFilter过滤器之前
    http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);


    return http.build();
}

@Autowired
private MyUserDetailServerImpl myUserDetailsService;



/*
* 验证管理器
* */
    @Bean
    public AuthenticationManager authenticationManager(PasswordEncoder passwordEncoder){
        DaoAuthenticationProvider provider=new DaoAuthenticationProvider();
//将编写的UserDetailsService注入进来
        provider.setUserDetailsService(myUserDetailsService);
//将使用的密码编译器加入进来
        provider.setPasswordEncoder(passwordEncoder);
//将provider放置到AuthenticationManager 中
        ProviderManager providerManager=new ProviderManager(provider);
        return providerManager;
    }


//跨域配置
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("*"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    /*
    * 密码加密器*/
@Bean
    public PasswordEncoder passwordEncoder(){
    return new BCryptPasswordEncoder();
}

}

在security的配置类中,设置了跨域问题、拦截器链的配置(并将一些需要放行的接口放行,将我们自定义的Jwt拦截器加入了security拦截链)、密码编译器、AuthenticationManager 验证管理等等一系列配置;

Usercontroller控制器:

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

    @Autowired
    private UserService userService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @PostMapping("/login")
    public Result<String> login(@RequestBody DtoLogin dtoLogin) {
        System.out.println(dtoLogin);
        String token = userService.login(dtoLogin);
        return Result.successData(token);
    }

    @PostMapping("/register")
    public Result register(@RequestBody DtoLogin dtoLogin) {
        System.out.println(dtoLogin);
        TUser user = new TUser();
        user.setLoginAct(dtoLogin.getUsername());
        user.setLoginPwd(passwordEncoder.encode(dtoLogin.getPassword()));
        userService.save(user);
        return Result.success();

    }
    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private JwtUtil jwtUtil;

    @GetMapping("/logout")
    public Result logout(@RequestHeader("token")String token){
        Integer id = jwtUtil.getUsernameFromToken(token);
        redisTemplate.delete(String.valueOf(id));

        return Result.success();
    }

    @GetMapping("/info")
    public Result info(@RequestHeader("token")String token){
        System.out.println("controller层获取到的token=======>"+token);
        Integer id = jwtUtil.getUsernameFromToken(token);
        String redisUser = redisTemplate.opsForValue().get(String.valueOf(id));
        MyTUserDetail myTUserDetail = JSON.parseObject(redisUser, MyTUserDetail.class);
        return Result.successData(myTUserDetail);

    }

}

在UserController控制器中,由于登录方法比较复杂,我将登录方法重新在service中重写了,剩下的获取用户信息、用户注册、退出登录都直接在UseController中实现了;

service中重写的登录方法:
 

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    private JwtUtil jwtUtil;


    @Override
    public String login(DtoLogin dtoLogin) {
        String codeRedis = redisTemplate.opsForValue().get(dtoLogin.getCodeKey());
        if (!dtoLogin.getCodeValue().equals(codeRedis)){
            throw new ResultException(400,"验证码错误");
        }
        // 验证码正确,删除redis中的验证码
        redisTemplate.delete(dtoLogin.getCodeKey());

        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(dtoLogin.getUsername(),dtoLogin.getPassword());

        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        if(authenticate==null){
            throw new  ResultException(400,"用户名或密码错误");
        }
//        获取返回的用户信息
        Object principal = authenticate.getPrincipal();

        MyTUserDetail myTUserDetail=(MyTUserDetail) principal;
        System.out.println(myTUserDetail);
//        使用Jwt生成token,并将用户的id传入
        String token = jwtUtil.generateToken(myTUserDetail.getTUser().getId());
        redisTemplate.opsForValue().
                set(String.valueOf(myTUserDetail.getTUser().getId()), JSON.toJSONString(myTUserDetail),1, TimeUnit.DAYS);


        return token;
    }

}

由于我们还是用了验证码,所以在这个登录方法中先判断了验证码、如果验证码正确。那么在判断传回来的用户名和密码。如果都正确,那么用Jwt返回一个token,token中携带的是用户的id;

至此,我们所有的前后端代码都已经写完了。那么,让我们具体的实验一下;

运行:

由于我刚创建的表,还没有添加数据,那么我现在前端点击注册,写入几条用户信息;

前后端分离,使用vue3整合SpringSecurity加JWT实现登录校验,spring boot整合第三方技术,vue.js,spring boot,securtty

写入信息之后,我使用刚注册过的用户来登录一下:

前后端分离,使用vue3整合SpringSecurity加JWT实现登录校验,spring boot整合第三方技术,vue.js,spring boot,securtty

注册成功之后,就会进入到我们自定义个Layout.vue组件内:

前后端分离,使用vue3整合SpringSecurity加JWT实现登录校验,spring boot整合第三方技术,vue.js,spring boot,securtty

现在,我点击“获取用户信息”按钮,因为这个路径我们并没有放行,那么他访问时就会被我们自定义的Jwt拦截器拦截,并验证它请求头中携带的token是否正确。如果正确,则放行。如果不正确,那么就会放行到登录拦截器中。

前后端分离,使用vue3整合SpringSecurity加JWT实现登录校验,spring boot整合第三方技术,vue.js,spring boot,securtty

可以看到,在控制台中打印出了用户的信息。这是肯定的,因为它这次请求携带的token是正确的,那么如果我们修改一下token的值,他还能正常访问到用户信息这个接口吗?

前后端分离,使用vue3整合SpringSecurity加JWT实现登录校验,spring boot整合第三方技术,vue.js,spring boot,securtty

我修改了请求头中的token信息,可以看到立马这个请求就被拦截了。并爆出了403错误;

现在,我点击“退出登录”按钮,它应该删除useToken中的token值,并且跳转到登录页面。后端也会删除redsi中存储的用户数据;

前后端分离,使用vue3整合SpringSecurity加JWT实现登录校验,spring boot整合第三方技术,vue.js,spring boot,securtty

现在,我们所有的任务都已经完成了。

我再整体理一下具体的思路:

前端发送请求后端,如果是登录请求,那么直接走登录接口即可,我将登录接口进行了方行,任何人都可以访问到登录接口,并且执行登录接口的逻辑;如果登录成功,会返回一个token,前后会将这个token存到useToken中,并且再以后的每次请求中都携带token;如果登录失败,返回一个报错信息即可。

如果前端发送的不是登录接口,但是前端携带可正确的token,那么会被我们自定义的Jwt拦截器拦截,并从中读取用户信息,放到security中共后续的拦截器使用;如果没有携带token,或者token不正确,那么后端会直接返回403的状态码提示;文章来源地址https://www.toymoban.com/news/detail-817595.html

到了这里,关于前后端分离,使用vue3整合SpringSecurity加JWT实现登录校验的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • SpringSecurity实现前后端分离登录token认证详解

    目录 1. SpringSecurity概述 1.1 权限框架 1.1.1 Apache Shiro 1.1.2 SpringSecurity 1.1.3 权限框架的选择 1.2 授权和认证 1.3 SpringSecurity的功能 2.SpringSecurity 实战 2.1 引入SpringSecurity 2.2 认证 2.2.1 登录校验流程  2.2.2 SpringSecurity完整流程  2.2.3 认证流程详解 2.3 思路分析 2.4 代码实战 2.4.1  自定义

    2024年02月08日
    浏览(32)
  • 整合vue elementui springboot mybatisplus前后端分离的 简单增加功能 删改查未实现

    涉及知识点 1.springboot项目启动创建  配置yml文件 2.mybatisplus的使用 3.vue的vite文件配置 4.vue springboot 前后端数据交互 1.建立项目的配置文件 src/main/resources/application.yml 2.建立项目 pom.xml 3.建立数据库表 4.建立实体类 cn.webrx.pojo.User 5.建立项目入口程序App cn.webrx.App 6.建立sevices axi

    2024年02月07日
    浏览(30)
  • node+vue3+mysql前后分离开发范式——实现视频文件上传并渲染

    大家好,我是yma16,本文分享关于 node+vue3+mysql前后分离开发范式——实现视频文件上传并渲染。 技术选型 前端:vite+vue3+antd 后端:node koa 数据库:mysql koa是一个现代的Node.js框架,可以用来构建Web应用程序。 Node.js的mime库 Node.js的mime库是用于根据文件扩展名获取对应的MIME类型

    2024年02月19日
    浏览(36)
  • SSM(Vue3+ElementPlus+Axios+SSM前后端分离)--功能实现[五]

    需求分析/图解 思路分析 完成后台代码从dao - serivce - controller , 并对每层代码进行测试 完成前台代码,使用axios 发送http 请求,完成带条件查询分页显示 代码实现 修改FurnService.java 和FurnServiceImpl.java , 增加条件查询 修改FurnService.java 修改FurnServiceImpl.java 修改FurnController.java , 处

    2024年02月14日
    浏览(22)
  • SSM(Vue3+ElementPlus+Axios+SSM前后端分离)--具体功能实现【三】

    需求分析/图解 思路分析 完成后台代码从dao - serivce - controller , 并对每层代码进行测试, 到controller 这一层,使用Postman 发送http post 请求完成测试 完成前端代码, 使用axios 发送ajax(json 数据)给后台, 实现添加家居信息 代码实现 创建srcmainjavacomnlcfurnsserviceFurnService.java 和src

    2024年02月14日
    浏览(27)
  • 开源django+mysql+vue3前后端分离商城baykeShop使用指南

    baykeShop(拜客商城系统)是一款全开源Python栈商城系统,后端依托django强大的框架体系,本项目融合了django的传统模版体系,同时轻微结合了前后端分离的开发方式,在不同场景选择了不同的技术栈,使其更具学习和研究价值,并且很好的打包为一个Python包文件,使其二次开

    2024年02月11日
    浏览(45)
  • Spring Boot 整合SpringSecurity和JWT和Redis实现统一鉴权认证

    本文主要讲了Spring Security文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是青衿🥇 ☁️博客首页:CSDN主页放风讲故事 🌄每日一句:努力一点,优秀一点 Spring Security Spring Security是一个强大且高度可定制的身份验证和访问控制框架。它是保护基

    2024年02月05日
    浏览(38)
  • node+vue3+mysql前后分离开发范式——实现对数据库表的增删改查

    大家好,我是yma16,本文分享关于 node+vue3+mysql前后分离开发范式——实现对数据库表的增删改查。 技术选型 前端:vite+vue3+antd 后端:node koa 数据库:mysql koa是一个现代的Node.js框架,可以用来构建Web应用程序。 Vue.js 是一款用于构建用户界面的开源JavaScript框架。Vue.js 3 是 Vu

    2024年02月20日
    浏览(26)
  • SpringSecurity(07)——JWT整合

    OncePerRequestFilter:在每次请求时只执行一次过滤,保证一次请求只通过一次filter,而不需要重复执行 login.html BasicAuthenticationFilter:OncePerRequestFilter执行完后,由BasicAuthenticationFilter检测和处理 http basic认证 ,取出请求头中的jwt,校验jwt 当BasicAuthenticationFilter认证失败的时候会进

    2024年01月21日
    浏览(31)
  • SpringBoot整合SpringSecurity和JWT

    JWT 1.介绍: 全称 JSON Web Token ,通过数字签名的方式,以 JSON 为载体,在不同的服务终端之间安全的传递信息。 常用于授权认证,用户登录后的每个请求都包含 JWT ,后端处理请求之前都要进行校验。 2.组成: Header :数据头,令牌类型和加密算法 Payload :负载,请求体和其他

    2024年02月03日
    浏览(28)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包