SpringBoot+Vue+SpringSecurity+JWT实现登录

前后端代码:GitHub地址

Vue-Cli创建前端项目

image-20210518083619085

前端项目目录结构

我们需要Login.vue和Home.vue组件,一个用于登录,一个用于登录成功之后的跳转。

我们需要封装一些函数,这些函数用于在前后端交互时请求与响应的拦截。定义api.js

我们还需要删除原有的组件,清除App.vue的内容(不能删除)。

image-20210518091931031

引入Element-ui

参考element-ui官网

在main.js文件中引入Element-ui

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI)

在VScode终端输入npm i element-ui -S

image-20210518085600049

在main.js中引入element-ui

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI);

可以在package.json中查看是否引入成功

  "dependencies": {
    "element-ui": "^2.15.1",
    "vue": "^2.5.2",
    "vue-router": "^3.0.1"
  },
代码实现:
Login.vue
<template>
  <div>
    <el-form ref="loginform" :rules="rules" :model="loginForm" class="loginContainer">
      <h3 class="loginTitle">系统登录</h3>
      <el-form-item prop="username">
        <!-- auto-complete="off"  禁止浏览器表单自动填充 -->
        <!-- placeholder  输入框占位文本 -->
        <el-input type="text" auto-complete="off" v-model="loginForm.username" placeholder="请输入用户名"></el-input>
      </el-form-item>

      <el-form-item prop="password">
        <el-input type="password" v-model="loginForm.password" auto-complete="off" placeholder="请输入密码" ></el-input>
      </el-form-item>

      <el-form-item prop="code">
        <el-input type="text" v-model="loginForm.code" size="normal" placeholder="点击图片更换验证码" auto-complete="off" style="width:250px;margin-right:5px"></el-input>
        <img :src="captchaUrl" @click="updataCaptcha">
      </el-form-item>

      <el-button type="primary" style="width:100%" @click="submitLogin">登录</el-button>

    </el-form>
  </div>
</template>

<script>
import {postRequest} from "../utils/api";
export default {
  name:"Login",
  data(){
    return{
      captchaUrl:'captcha?time' + new Date(),
      loginForm:{
        username:'',
        password:'',
        code:''
      },
      // rules  表单的验证  required   message:提示信息
      rules:{
        username:[{required:true,message:'请输入用户名',trigger:'blur'}],
        password:[{required:true,message:'请输入密码',trigger:'blur'}],
        code:[{required:true,message:'请输入验证码',trigger:'blur'}]
      }
    }
  },
  methods:{
    //点击更新图片
    updataCaptcha(){
      this.captchaUrl = 'captcha?time=' + new Date();
      },
    
    //登录
    submitLogin(){
      this.$refs.loginForm.validate((valid) => {
        if(valid){
          postRequest('/login',this.loginForm).then(resp => {
            console.log(resp);
            if(resp){
              const token = resp.object.tokenHead + resp.object.token;
              window.sessionStorage.setItem('tokenStr',token)
              this.$router.replace('/Home')
            }
          })
        }else{
          console.log('error submit');
          return false;
        }
      })
    }
  }
}
</script>

<style>
  .loginContainer{
        border-radius: 15px;
        background-clip: padding-box;
        margin: 180px auto;
        width: 350px;
        padding: 15px 35px 15px 35px;
        background:#fff;
        border: 1px solid #eaeaea;
        box-shadow: 0 0 25px #cac6c6;
  }

  .loginTitle{
        margin: 0px auto 40px auto;
        text-align: center;
  }
</style>
Api.js
import axios from 'axios'
import { Message } from 'element-ui'
import router from '../router'


//请求拦截器
axios.interceptors.request.use(config => {
    if(window.sessionStorage.getItem('tokenStr')){
        //请求携带token
        config.headers['Authorization'] = window.sessionStorage.getItem('tokenStr');
    }
    return config
},error => {
    console.log(error);
})



//响应拦截器
// success 成功调到后端接口之后,但是接口不允许进行该操作
axios.interceptors.response.use(success =>{
    if(success.status && success.status == 200){
        if(success.data.code == 500 || success.data.code == 401 || success.data.code == 403){
            Message.error({message:success.data.message});
            return;
        }

        if(success.data.message){
            Message.success({message:success.data.message})
        }
    }
    return success.data;
},error=>{
    //没有访问到接口
    if(error.response.code == 504 || error.response.code == 404){
        Message.error({message:'服务器崩了'});
    }else if(error.response.code == 403){
        Message.error({message:'权限不足'})
    }else if(error.response.code == 401){
        Message.error({message:'未登录'})
        router.replace('/')
    }else{
        if(error.response.data.message){
            Message.error({message:error.response.data.message})
        }else{
            Message.error({message:'未知错误'})
        }
    }
})




let base = '';

export const postRequest = (url,params) => {
    return axios({
        method:'post',
        url:`${base}${url}`,
        data:params
    })
}
跨域

在index.js中

proxyTable: {
  '/ws':{
       ws:true,
       target: 'ws://localhost:8081'
   },
   '/':{
       ws: false,
       target: 'http://localhost:8081',
       changeOrigin: true,
       pathRewrite: {
       '^/': '/'
    }
}

后端:

Config

​ CaptchaConfig: 验证码配置文件

​ JwtTokenFilter:JWT过滤器,判断受否拿到JWT,判断JWT是否有效

​ SecurityConfig:SpringSecurity 核心配置文件

Controller

​ CaptchaController:生成验证码

​ LoginController:登录

dao

​ AdminMapper:数据库查询

pojo

​ Admin:实现 UserDetails接口

​ LoginAdmin:用于接收前端传来的信息,属性有:用户名,密码,验证码

service

​ AdminServiceImpl:用于登录的主要逻辑

utils

​ JWTUtils:生成JWT

​ Respbean:向前端返回结果类

项目框架

image-20210518145507364

引入依赖
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

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

    <!--lombok 依赖-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>


    <!--mysql 依赖-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.2.0</version>
    </dependency>

    <!--   jwt依赖-->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.0</version>
    </dependency>

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

    <!--验证码-->
    <dependency>
        <groupId>com.github.axet</groupId>
        <artifactId>kaptcha</artifactId>
        <version>0.0.9</version>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <scope>test</scope>
    </dependency>


</dependencies>
配置文件
server.port=8081


# mybatis配置
spring.datasource.url=jdbc:mysql://localhost:3306/login
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root

# mybatis配置文件
mybatis.mapper-locations=classpath*:/Mappers/*.xml

# 日志
# logging.level.root=debug


# Jwt存储的请求头
jwt-tokenHeader=Authorization
# Jwt加密秘钥
jwt-secret=yeb-secret
# Jwt 的超期限时间(60*60)*24
jwt-expiration=604800
# Jwt负载中拿到开头  后端需要用来判断是不是需要的token
jwt-tokenHead=Bearer
LoginController
@RestController
public class LoginController {

    @Autowired
    private AdminServiceImpl adminService;


    @PostMapping("/login")
    public RespBean login(@RequestBody LoginAdmin loginAdmin, HttpServletRequest request){
        return adminService.login(loginAdmin.getUsername(),loginAdmin.getPassword(),loginAdmin.getCode(),request);
    }
    
}
LoginServiceImpl
@Service
public class AdminServiceImpl implements AdminService {

    @Autowired
    private AdminMapper adminMapper;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private JWTUtils jwtUtils;

    @Value("${jwt-tokenHead}")
    private String tokenHead;

    @Override
    public Admin selectAdminByName(String name) {
        return adminMapper.selectOne(name);
    }

    @Override
    public RespBean login(String username, String password, String code, HttpServletRequest request) {
		//验证码验证
        String captcha = (String)request.getSession().getAttribute("captcha");
        System.out.println(captcha);
        if(StringUtils.isEmpty(code) || !captcha.equalsIgnoreCase(code)){
            return RespBean.error("验证码错误,请重新输入");
        }

        //得到用户信息
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        System.out.println(userDetails);
        //用户信息为空,且密码不正确 返回错误

        if(null == userDetails || !passwordEncoder.matches(password,userDetails.getPassword())){
            return RespBean.error("用户名或密码错误");
        }

        if(!userDetails.isEnabled()){
            return RespBean.error("账号被禁用,请联系管理员");
        }

        //更新security登录用户对象

        /***
         * 以UsernamePasswordAuthenticationToken实现的带用户名和密码以及权限的Authentication
         */
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
		
        //将当前登录的信息设置到Spring Security 上下文
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
		
        //创建token 
        String token = jwtUtils.generateToken(userDetails);

        //将token和tokenHead传入前端
        Map<String, String> map = new HashMap<>();
        map.put("token",token);
        map.put("tokenHead",tokenHead);
		
        return RespBean.success("登录成功",map);
    }
}

SecurityConfig

/***
 * SpringSecurity  配置类
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AdminServiceImpl adminService;

    
    //重写loadUserByUsername()  lambda表达式
    @Override
    @Bean
    protected UserDetailsService userDetailsService() {
        return username -> {
            Admin admin = adminService.selectAdminByName(username);

            if(null != admin){
                return admin;
            }

            throw new UsernameNotFoundException("用户名或密码不正确");
        };
    }


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

    //根据传入的自定义UserDetailsService添加身份验证。
    // 允许自定义身份验证。
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
    }

    @Bean
    public JwtTokenFilter jwtTokenFilter(){
        return new JwtTokenFilter();
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf()
                .disable()
                //基于token 不需要session
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                //允许登录访问
                .antMatchers("/login","/logout")
                .permitAll()
                //除了上面,所有请求都要求认证
                .anyRequest()
                .authenticated()
                .and()
                .headers()
                .cacheControl();


        //添加jwt验证过滤器
        http.addFilterBefore(jwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}
  • 0
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring Boot和Vue.js是两个非常流行的技术栈,可以非常好地实现前后端分离的开发模式。SecurityJWT是两个很好的工具,可以帮助我们实现安全的登录和授权机制。 以下是实现Spring Boot和Vue.js前后端分离的步骤: 1.创建Spring Boot工程 首先,我们需要创建一个Spring Boot工程,可以使用Spring Initializr来生成一个基本的Maven项目,添加所需的依赖项,包括Spring SecurityJWT。 2.配置Spring SecuritySpring Security中,我们需要定义一个安全配置类,该类将定义我们的安全策略和JWT的配置。在这里,我们可以使用注解来定义我们的安全策略,如@PreAuthorize和@Secured。 3.实现JWT JWT是一种基于令牌的身份验证机制,它使用JSON Web Token来传递安全信息。在我们的应用程序中,我们需要实现JWT的生成和验证机制,以便我们可以安全地登录和授权。 4.配置Vue.js 在Vue.js中,我们需要创建一个Vue.js项目,并使用Vue CLI来安装和配置我们的项目。我们需要使用Vue Router来定义我们的路由,并使用Axios来发送HTTP请求。 5.实现登录和授权 最后,我们需要实现登录和授权机制,以便用户可以安全地登录和访问我们的应用程序。在Vue.js中,我们可以使用Vue Router和Axios来发送HTTP请求,并在Spring Boot中使用JWT来验证用户身份。 总结 以上是实现Spring Boot和Vue.js前后端分离的步骤,我们可以使用SecurityJWT实现安全的登录和授权机制。这种开发模式可以让我们更好地实现前后端分离,提高我们的开发效率和应用程序的安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值