vue +springboot + jwt 单点登录 实例

打印 上一主题 下一主题

主题 1871|帖子 1871|积分 5613


  • springboot 代码

    首先在entity 新建实体,新建代码
  1. package com.example.demo.demos.web.demo.entity;
  2. import lombok.Data;
  3. @Data
  4. public class User {
  5.     private String username;
  6.     private String password;
  7.     private String token;
  8. }
复制代码

  • controller 中写

  1.     //定义两个初始常量登录名 这里不使用数据库认证
  2.     private final String USERNAME = "admin";
  3.     private final String PASSWORD = "admin";
  4.     @GetMapping("/login")
  5.     public User login(  User loginForm){
  6.         if(USERNAME.equals(loginForm.getUsername()) && PASSWORD.equals(loginForm.getPassword())){
  7.             //添加token
  8.             loginForm.setToken(JwtUtiles.createToken());
  9.             return loginForm;
  10.         }
  11.         return null;
  12.     }
复制代码
添加相关依赖
  1.         <dependency>
  2.             <groupId>io.jsonwebtoken</groupId>
  3.             <artifactId>jjwt</artifactId>
  4.             <version>0.9.1</version>
  5.         </dependency>
  6.         <!---  注意以下是  java1.8以上需要添加--->
  7.         <dependency>
  8.             <groupId>javax.xml.bind</groupId>
  9.             <artifactId>jaxb-api</artifactId>
  10.             <version>2.3.0</version>
  11.         </dependency>
  12.         <dependency>
  13.             <groupId>com.sun.xml.bind</groupId>
  14.             <artifactId>jaxb-core</artifactId>
  15.             <version>2.3.0</version>
  16.         </dependency>
  17.         <dependency>
  18.             <groupId>com.sun.xml.bind</groupId>
  19.             <artifactId>jaxb-impl</artifactId>
  20.             <version>2.3.0</version>
  21.         </dependency>
  22.         <dependency>
  23.             <groupId>javax.activation</groupId>
  24.             <artifactId>activation</artifactId>
  25.             <version>1.1.1</version>
  26.         </dependency>
复制代码
utils 中新建 文件JwtUtiles

  1. package com.example.demo.demos.web.demo.utils;
  2. import io.jsonwebtoken.JwtBuilder;
  3. import io.jsonwebtoken.Jwts;
  4. import io.jsonwebtoken.SignatureAlgorithm;
  5. import java.util.Date;
  6. import java.util.UUID;
  7. public class JwtUtiles {
  8.     private static  long time = 1000* 60 *60 *24;//token有效时间
  9.     private static String signature = "admin";
  10.     public static String createToken(){
  11.         JwtBuilder jwtBuilder  = Jwts.builder();
  12.         String jwtToken = jwtBuilder
  13.                 .setHeaderParam("typ","JWT")
  14.                 .setHeaderParam("alg","HS256")
  15.                 .claim("username","admin")
  16.                 .claim("role","admin")
  17.                 .setSubject("admin-test")
  18.                 .setExpiration(new Date(System.currentTimeMillis()+time))
  19.                 .setId(UUID.randomUUID().toString())
  20.                 .signWith(SignatureAlgorithm.HS256,signature)
  21.                 .compact();
  22.         return jwtToken;
  23.     }
  24. }
复制代码
前端vue 写法:
request.js 设置

  1. import axios from 'axios'
  2. const request = axios.create({
  3.         baseURL: 'http://localhost:8080',
  4.     timeout: 50000
  5. })
  6. // request 拦截器
  7. // 可以自请求发送前对请求做一些处理
  8. // 比如统一加token,对请求参数统一加密
  9. request.interceptors.request.use(config => {
  10.     config.headers['Content-Type'] = 'application/json;charset=utf-8';
  11.     let user=localStorage.getItem("user")?JSON.parse(localStorage.getItem("user")):{}//获取登录时存放的user对象信息
  12.     config.headers['token'] = user.token;  // 设置请求头
  13.     return config
  14. }, error => {
  15.     return Promise.reject(error)
  16. });
  17. // response 拦截器
  18. // 可以在接口响应后统一处理结果
  19. request.interceptors.response.use(
  20.     response => {
  21.         let res = response.data;
  22.         // 如果是返回的文件
  23.         if (response.config.responseType === 'blob') {
  24.             return res
  25.         }
  26.         // 兼容服务端返回的字符串数据
  27.         if (typeof res === 'string') {
  28.             res = res ? JSON.parse(res) : res
  29.         }
  30.         return res;
  31.     },
  32.     error => {
  33.         console.log('err' + error) // for debug
  34.         return Promise.reject(error)
  35.     }
  36. )
  37. export default request
复制代码
login.vue 界面
  1. <template>
  2.     <div class="login_container">
  3.        <div class="login_box">
  4.          <div style="margin:20px 0; text-align:center; font-size:24px" ><b>登录</b></div>
  5.          <!-- 用户名-->
  6.          <el-form ref="LoginFormRef" :model="loginForm" :rules="LoginFormRules" >
  7.            <el-form-item prop="username">
  8.              <el-input size="medium" style="margin:10px 0px;width: 300px;margin-left:25px" v-model="loginForm.username" prefix-icon="el-icon-user"></el-input>
  9.            </el-form-item>
  10.          <!-- 密码-->
  11.             <el-form-item prop="password">
  12.               <el-input size="medium" style="margin:10px 0px;width: 300px;margin-left:25px" show-password v-model="loginForm.password" prefix-icon="el-icon-lock" type="password"></el-input>
  13.            </el-form-item>
  14.            <div style="margin:10px 0; text-align:center">
  15.              <el-button type="primary" size="small" @click="login" >登录</el-button>
  16.            <!--   <el-button type="warning" size="small" @click="resetLoginForm">重置</el-button> -->
  17.            </div>
  18.          </el-form>
  19.        </div>
  20.      </div>
  21.    </template>
  22.    
  23.    <script>
  24.      export default {
  25.        name:"Login",
  26.        data() {
  27.          return {
  28.            loginForm: {
  29.              username:'',
  30.              password:''
  31.            },
  32.            LoginFormRules:{
  33.              username:[
  34.                { required: true, message: '请输入用户名', trigger: 'blur' },
  35.              ],
  36.              password:[
  37.                { required: true, message: '请输入密码', trigger: 'blur' },
  38.              ]
  39.            }
  40.          }
  41.        },   
  42.        methods:{
  43.         login(){
  44.             this.$refs['LoginFormRef'].validate(async (valid) => {
  45.                 if (valid) {
  46.                   let _this = this;
  47.                     this.request.get("http://localhost:8080/user/login",{params:this.loginForm}).then(res=>{
  48.                       console.log(this.loginForm)
  49.                     console.log(res)
  50. /*                             if(res.code=='200'){
  51.                                 localStorage.setItem("user",JSON.stringify(res.data));//存储用户信息到浏览器
  52.                                 this.$router.push("/home");
  53.                                 this.$message.success("登录成功");
  54.                             }else{
  55.                                 this.$message.error(res.msg);
  56.                             } */
  57.                     })
  58.                 }  
  59.             })
  60.        },
  61.      }
  62.    
  63.     }
  64.    </script>
  65.    
  66.    <style scoped>
  67.      .login_container{
  68.        background-color: #2b4b6b;
  69.        height: 100%;
  70.      }
  71.    
  72.      .login_box{
  73.        width: 350px;
  74.        height: 300px;
  75.        background-color: #fff;
  76.        border-radius: 3px;
  77.        position: absolute;
  78.        left: 50%;
  79.        top: 50%;
  80.        transform: translate(-50%,-50%)
  81.      }
  82.    </style>
复制代码

登录后可观察到token已经返回

添加路由保卫

  1. import Vue from 'vue'
  2. import VueRouter from 'vue-router'
  3. import Manage from '../views/Manage.vue'
  4. import Aside from '@/components/Aside.vue'
  5. import User from '@/views/user.vue'
  6. import Login  from '../views/Login.vue'
  7. import axios from 'axios'
  8. Vue.use(VueRouter)
  9. const routes = [
  10.   {
  11.     path: '/',
  12.     name: 'Manage',
  13.     redirect: '/login',
  14.     component: Manage,
  15.     children:[
  16.       {
  17.         path: 'user',
  18.         name: 'User',
  19.         component: User
  20.       },
  21.       {
  22.         path: 'home',
  23.         name: 'Home',
  24.         // route level code-splitting
  25.         // this generates a separate chunk (about.[hash].js) for this route
  26.         // which is lazy-loaded when the route is visited.
  27.         component: () => import(/* webpackChunkName: "about" */ '../views/Home.vue')
  28.       }
  29.     ]
  30.   },
  31.   {
  32.     path: '/login',
  33.     name: 'Login',
  34.     component: Login
  35.   },
  36.   {
  37.     path: '/error',
  38.     name: 'Error',
  39.     component: Login
  40.   }
  41. ]
  42. const router = new VueRouter({
  43.   mode: 'history',
  44.   base: process.env.BASE_URL,
  45.   routes
  46. })
  47. //全局路由守卫
  48. router.beforeEach((to,from,next)=>{
  49.   if(to.path.startsWith('/login')){
  50.     window.localStorage.removeItem('access-admin')
  51.     next()
  52.   }else{
  53.     let admin = JSON.parse(window.localStorage.getItem('access-admin'))
  54.     console.log(admin)
  55.     if(!admin ){
  56.       next({path:'/login'})
  57.       location.reload()
  58.     }else{//检查token合法性
  59.       let token = admin.token
  60.       console.log(token)
  61.       axios({
  62.         url:"http://localhost:8080/user/checkToken",
  63.         method:'get',
  64.         Headers:{
  65.           token:admin.token
  66.         },
  67.         params:{
  68.           token:token
  69.         }
  70.       }).then((response) =>{
  71.         console.log(response.data)
  72.         if(!response.data ){ console.log('校验失败')
  73.         //  next({path:'/login'})
  74.      
  75.       
  76.         next({path:'/login'})
  77.         location.reload()
  78.         }
  79.          
  80.       })
  81.       next();
  82.     }
  83.   }
  84. })
  85. const originalPush = VueRouter.prototype.push
  86. VueRouter.prototype.push = function push(location, onResolve, onReject) {
  87. if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
  88. return originalPush.call(this, location).catch(err => err)
  89. }
  90. export default router
复制代码
设置到期拦截

  1. package com.example.demo.demos.web.demo.controller;import cn.hutool.core.util.StrUtil;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.baomidou.mybatisplus.core.metadata.IPage;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;import com.example.demo.demos.web.demo.common.Constants;import com.example.demo.demos.web.demo.common.Result;import com.example.demo.demos.web.demo.entity.User;import com.example.demo.demos.web.demo.entity.UserDTO;import com.example.demo.demos.web.demo.entity.UserEntity;import com.example.demo.demos.web.demo.mapper.UserMapper;import com.example.demo.demos.web.demo.service.UserService;import com.example.demo.demos.web.demo.utils.JwtUtiles;import org.apache.ibatis.annotations.Param;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import java.util.HashMap;import java.util.List;import java.util.Map;@RestController@RequestMapping("user")public class UserController {   // @Autowired   // private UserMapper userMapper;    @Autowired    public UserService userService;/*        @GetMapping("/")        public List<UserEntity> index(){            return userMapper.findAll();        }*/    //使用mybtis-plus实现查询所有数据    @GetMapping("/")    public List<UserEntity> findAll(){        return userService.list();    }       /* @PostMapping("/add")        //这里做了一个单纯的添加的示例,使用的是mapper中的insert方法        public Integer save(@RequestBody UserEntity userEntity){                return userService.save(userEntity);        }*//*        @DeleteMapping("/{id}")        public Integer deleteById(@PathVariable Integer id){                return  userService.deleteById(id);        }*/    //使用mybtis-plus实现删除    @DeleteMapping("/{id}")    public boolean deleteById(@PathVariable Integer id){        return  userService.removeById(id);    }    @PostMapping    //使用mybtis-plus,注意这里返回的是boolean型    public Boolean save(@RequestBody UserEntity user) {        return userService.saveUser(user);    }    //使用mybtis-plus实现批量删除    @PostMapping("/del/batch/")    public boolean deleteBatch(@RequestBody List<Integer> ids){        return userService.removeByIds(ids);    }    //分页查询    //接口路径user/page?pageNum=1&pageSize=10    //RequestParam接受前台传过来的第几页,每页显示数/*    @GetMapping("/page")    public Map<String,Object> findPage(@RequestParam Integer pageNum,@RequestParam Integer pageSize){        pageNum=(pageNum-1)*pageSize;        List<UserEntity> data=userService.selectPage(pageNum,pageSize);        Integer total=userMapper.selectTotal();        Map<String,Object> res=new HashMap<>();        res.put("data",data);        res.put("total",total);        return res;    }*/    //使用mybtis-plus实现根据ID查找记载    @GetMapping("/{id}")    public UserEntity findOne(@PathVariable Integer id){        return userService.getById(id);    }    //使用mybtis-plus实现模糊查询并分页    @GetMapping("/page")    public IPage<UserEntity> findPage(@RequestParam Integer pageNum,                                      @RequestParam Integer pageSize,                                      @RequestParam(defaultValue = "") String username,                                      @RequestParam(defaultValue = "") String nickname,                                      @RequestParam(defaultValue = "") String address){        IPage<UserEntity> page=new Page<>(pageNum,pageSize);        QueryWrapper<UserEntity> queryWrapper=new QueryWrapper<>();        queryWrapper.like("username",username);        queryWrapper.like("nickname",nickname);        queryWrapper.like("address",address);        return userService.page(page,queryWrapper);    }/*    @PostMapping("/login")    public Result login(@RequestBody UserDTO userDTO){        String username=userDTO.getUsername();//先对userDTO举行是否为空的校验        String password=userDTO.getPassword();        //调用hutool工具中的StrUtil函数实现用户名和密码是否为空的判断        if(StrUtil.isBlank(username) || StrUtil.isBlank(password)){            return Result.error(Constants.CODE_400,"参数错误");        }        UserDTO dto=userService.login(userDTO);        return Result.success(dto);    }*/    //定义两个初始常量登录名 这里不使用数据库认证
  2.     private final String USERNAME = "admin";
  3.     private final String PASSWORD = "admin";
  4.     @GetMapping("/login")
  5.     public User login(  User loginForm){
  6.         if(USERNAME.equals(loginForm.getUsername()) && PASSWORD.equals(loginForm.getPassword())){
  7.             //添加token
  8.             loginForm.setToken(JwtUtiles.createToken());
  9.             return loginForm;
  10.         }
  11.         return null;
  12.     }
  13.     @GetMapping("/checkToken")    public Boolean checkToken(HttpServletRequest  request,@RequestParam String token){        String token1 = token;        return JwtUtiles.checkToken(token1);    }}
复制代码
写解析方法

  1. package com.example.demo.demos.web.demo.utils;
  2. import io.jsonwebtoken.JwtBuilder;
  3. import io.jsonwebtoken.Jwts;
  4. import io.jsonwebtoken.SignatureAlgorithm;
  5. import java.util.Date;
  6. import java.util.UUID;
  7. public class JwtUtiles {
  8.     private static  long time = 1000* 6;//token有效时间
  9.     private static String signature = "admin";
  10.     public static String createToken(){
  11.         JwtBuilder jwtBuilder  = Jwts.builder();
  12.         String jwtToken = jwtBuilder
  13.                 .setHeaderParam("typ","JWT")
  14.                 .setHeaderParam("alg","HS256")
  15.                 .claim("username","admin")
  16.                 .claim("role","admin")
  17.                 .setSubject("admin-test")
  18.                 .setExpiration(new Date(System.currentTimeMillis()+time))
  19.                 .setId(UUID.randomUUID().toString())
  20.                 .signWith(SignatureAlgorithm.HS256,signature)
  21.                 .compact();
  22.         return jwtToken;
  23.     }
  24.     public static boolean checkToken(String token){
  25.         if(token == null){
  26.             return false;
  27.         }
  28.         try {
  29.             Jwts.parser().setSigningKey(signature).parseClaimsJws(token);
  30.         } catch (Exception e) {
  31.             return  false;
  32.         }
  33.         return  true;
  34.     }
  35. }
复制代码
login 页面
  1. <template>
  2.     <div class="login_container">
  3.        <div class="login_box">
  4.          <div style="margin:20px 0; text-align:center; font-size:24px" ><b>登录</b></div>
  5.          <!-- 用户名-->
  6.          <el-form ref="LoginFormRef" :model="loginForm" :rules="LoginFormRules" >
  7.            <el-form-item prop="username">
  8.              <el-input size="medium" style="margin:10px 0px;width: 300px;margin-left:25px" v-model="loginForm.username" prefix-icon="el-icon-user"></el-input>
  9.            </el-form-item>
  10.          <!-- 密码-->
  11.             <el-form-item prop="password">
  12.               <el-input size="medium" style="margin:10px 0px;width: 300px;margin-left:25px" show-password v-model="loginForm.password" prefix-icon="el-icon-lock" type="password"></el-input>
  13.            </el-form-item>
  14.            <div style="margin:10px 0; text-align:center">
  15.              <el-button type="primary" size="small" @click="login" >登录</el-button>
  16.            <!--   <el-button type="warning" size="small" @click="resetLoginForm">重置</el-button> -->
  17.            </div>
  18.          </el-form>
  19.        </div>
  20.      </div>
  21.    </template>
  22.    
  23.    <script>
  24.      export default {
  25.        name:"Login",
  26.        data() {
  27.          return {
  28.            loginForm: {
  29.              username:'',
  30.              password:''
  31.            },
  32.            LoginFormRules:{
  33.              username:[
  34.                { required: true, message: '请输入用户名', trigger: 'blur' },
  35.              ],
  36.              password:[
  37.                { required: true, message: '请输入密码', trigger: 'blur' },
  38.              ]
  39.            }
  40.          }
  41.        },   
  42.        methods:{
  43.         login(){
  44.             this.$refs['LoginFormRef'].validate(async (valid) => {
  45.                 if (valid) {
  46.                   let _this = this;
  47.                     this.request.get("http://localhost:8080/user/login",{params:this.loginForm}).then(res=>{
  48.                     //  console.log(res)
  49.                       if(res != null){
  50.                         localStorage.setItem('access-admin',JSON.stringify(res))
  51.                         //跳转登录页
  52.                        // this.$router.replace({path:'/home'})
  53.                        this.$router.push("/home");
  54.                       }
  55.                    // console.log(res)
  56. /*                             if(res.code=='200'){
  57.                                 localStorage.setItem("user",JSON.stringify(res.data));//存储用户信息到浏览器
  58.                                 this.$router.push("/home");
  59.                                 this.$message.success("登录成功");
  60.                             }else{
  61.                                 this.$message.error(res.msg);
  62.                             } */
  63.                     })
  64.                 }  
  65.             })
  66.        },
  67.      }
  68.    
  69.     }
  70.    </script>
  71.    
  72.    <style scoped>
  73.      .login_container{
  74.        background-color: #2b4b6b;
  75.        height: 100%;
  76.      }
  77.    
  78.      .login_box{
  79.        width: 350px;
  80.        height: 300px;
  81.        background-color: #fff;
  82.        border-radius: 3px;
  83.        position: absolute;
  84.        left: 50%;
  85.        top: 50%;
  86.        transform: translate(-50%,-50%)
  87.      }
  88.    </style>
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

美食家大橙子

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表