IT评测·应用市场-qidao123.com技术社区
标题:
vue +springboot + jwt 单点登录 实例
[打印本页]
作者:
美食家大橙子
时间:
2024-12-10 13:51
标题:
vue +springboot + jwt 单点登录 实例
springboot 代码
首先在entity 新建实体,新建代码
package com.example.demo.demos.web.demo.entity;
import lombok.Data;
@Data
public class User {
private String username;
private String password;
private String token;
}
复制代码
controller 中写
//定义两个初始常量登录名 这里不使用数据库认证
private final String USERNAME = "admin";
private final String PASSWORD = "admin";
@GetMapping("/login")
public User login( User loginForm){
if(USERNAME.equals(loginForm.getUsername()) && PASSWORD.equals(loginForm.getPassword())){
//添加token
loginForm.setToken(JwtUtiles.createToken());
return loginForm;
}
return null;
}
复制代码
添加相关依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!--- 注意以下是 java1.8以上需要添加--->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
复制代码
utils 中新建 文件JwtUtiles
package com.example.demo.demos.web.demo.utils;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.UUID;
public class JwtUtiles {
private static long time = 1000* 60 *60 *24;//token有效时间
private static String signature = "admin";
public static String createToken(){
JwtBuilder jwtBuilder = Jwts.builder();
String jwtToken = jwtBuilder
.setHeaderParam("typ","JWT")
.setHeaderParam("alg","HS256")
.claim("username","admin")
.claim("role","admin")
.setSubject("admin-test")
.setExpiration(new Date(System.currentTimeMillis()+time))
.setId(UUID.randomUUID().toString())
.signWith(SignatureAlgorithm.HS256,signature)
.compact();
return jwtToken;
}
}
复制代码
前端vue 写法:
request.js 设置
import axios from 'axios'
const request = axios.create({
baseURL: 'http://localhost:8080',
timeout: 50000
})
// request 拦截器
// 可以自请求发送前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config => {
config.headers['Content-Type'] = 'application/json;charset=utf-8';
let user=localStorage.getItem("user")?JSON.parse(localStorage.getItem("user")):{}//获取登录时存放的user对象信息
config.headers['token'] = user.token; // 设置请求头
return config
}, error => {
return Promise.reject(error)
});
// response 拦截器
// 可以在接口响应后统一处理结果
request.interceptors.response.use(
response => {
let res = response.data;
// 如果是返回的文件
if (response.config.responseType === 'blob') {
return res
}
// 兼容服务端返回的字符串数据
if (typeof res === 'string') {
res = res ? JSON.parse(res) : res
}
return res;
},
error => {
console.log('err' + error) // for debug
return Promise.reject(error)
}
)
export default request
复制代码
login.vue 界面
<template>
<div class="login_container">
<div class="login_box">
<div style="margin:20px 0; text-align:center; font-size:24px" ><b>登录</b></div>
<!-- 用户名-->
<el-form ref="LoginFormRef" :model="loginForm" :rules="LoginFormRules" >
<el-form-item prop="username">
<el-input size="medium" style="margin:10px 0px;width: 300px;margin-left:25px" v-model="loginForm.username" prefix-icon="el-icon-user"></el-input>
</el-form-item>
<!-- 密码-->
<el-form-item prop="password">
<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>
</el-form-item>
<div style="margin:10px 0; text-align:center">
<el-button type="primary" size="small" @click="login" >登录</el-button>
<!-- <el-button type="warning" size="small" @click="resetLoginForm">重置</el-button> -->
</div>
</el-form>
</div>
</div>
</template>
<script>
export default {
name:"Login",
data() {
return {
loginForm: {
username:'',
password:''
},
LoginFormRules:{
username:[
{ required: true, message: '请输入用户名', trigger: 'blur' },
],
password:[
{ required: true, message: '请输入密码', trigger: 'blur' },
]
}
}
},
methods:{
login(){
this.$refs['LoginFormRef'].validate(async (valid) => {
if (valid) {
let _this = this;
this.request.get("http://localhost:8080/user/login",{params:this.loginForm}).then(res=>{
console.log(this.loginForm)
console.log(res)
/* if(res.code=='200'){
localStorage.setItem("user",JSON.stringify(res.data));//存储用户信息到浏览器
this.$router.push("/home");
this.$message.success("登录成功");
}else{
this.$message.error(res.msg);
} */
})
}
})
},
}
}
</script>
<style scoped>
.login_container{
background-color: #2b4b6b;
height: 100%;
}
.login_box{
width: 350px;
height: 300px;
background-color: #fff;
border-radius: 3px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%)
}
</style>
复制代码
登录后可观察到token已经返回
添加路由保卫
import Vue from 'vue'
import VueRouter from 'vue-router'
import Manage from '../views/Manage.vue'
import Aside from '@/components/Aside.vue'
import User from '@/views/user.vue'
import Login from '../views/Login.vue'
import axios from 'axios'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Manage',
redirect: '/login',
component: Manage,
children:[
{
path: 'user',
name: 'User',
component: User
},
{
path: 'home',
name: 'Home',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/Home.vue')
}
]
},
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/error',
name: 'Error',
component: Login
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
//全局路由守卫
router.beforeEach((to,from,next)=>{
if(to.path.startsWith('/login')){
window.localStorage.removeItem('access-admin')
next()
}else{
let admin = JSON.parse(window.localStorage.getItem('access-admin'))
console.log(admin)
if(!admin ){
next({path:'/login'})
location.reload()
}else{//检查token合法性
let token = admin.token
console.log(token)
axios({
url:"http://localhost:8080/user/checkToken",
method:'get',
Headers:{
token:admin.token
},
params:{
token:token
}
}).then((response) =>{
console.log(response.data)
if(!response.data ){ console.log('校验失败')
// next({path:'/login'})
next({path:'/login'})
location.reload()
}
})
next();
}
}
})
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location, onResolve, onReject) {
if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
return originalPush.call(this, location).catch(err => err)
}
export default router
复制代码
设置到期拦截
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); }*/ //定义两个初始常量登录名 这里不使用数据库认证
private final String USERNAME = "admin";
private final String PASSWORD = "admin";
@GetMapping("/login")
public User login( User loginForm){
if(USERNAME.equals(loginForm.getUsername()) && PASSWORD.equals(loginForm.getPassword())){
//添加token
loginForm.setToken(JwtUtiles.createToken());
return loginForm;
}
return null;
}
@GetMapping("/checkToken") public Boolean checkToken(HttpServletRequest request,@RequestParam String token){ String token1 = token; return JwtUtiles.checkToken(token1); }}
复制代码
写解析方法
package com.example.demo.demos.web.demo.utils;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.UUID;
public class JwtUtiles {
private static long time = 1000* 6;//token有效时间
private static String signature = "admin";
public static String createToken(){
JwtBuilder jwtBuilder = Jwts.builder();
String jwtToken = jwtBuilder
.setHeaderParam("typ","JWT")
.setHeaderParam("alg","HS256")
.claim("username","admin")
.claim("role","admin")
.setSubject("admin-test")
.setExpiration(new Date(System.currentTimeMillis()+time))
.setId(UUID.randomUUID().toString())
.signWith(SignatureAlgorithm.HS256,signature)
.compact();
return jwtToken;
}
public static boolean checkToken(String token){
if(token == null){
return false;
}
try {
Jwts.parser().setSigningKey(signature).parseClaimsJws(token);
} catch (Exception e) {
return false;
}
return true;
}
}
复制代码
login 页面
<template>
<div class="login_container">
<div class="login_box">
<div style="margin:20px 0; text-align:center; font-size:24px" ><b>登录</b></div>
<!-- 用户名-->
<el-form ref="LoginFormRef" :model="loginForm" :rules="LoginFormRules" >
<el-form-item prop="username">
<el-input size="medium" style="margin:10px 0px;width: 300px;margin-left:25px" v-model="loginForm.username" prefix-icon="el-icon-user"></el-input>
</el-form-item>
<!-- 密码-->
<el-form-item prop="password">
<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>
</el-form-item>
<div style="margin:10px 0; text-align:center">
<el-button type="primary" size="small" @click="login" >登录</el-button>
<!-- <el-button type="warning" size="small" @click="resetLoginForm">重置</el-button> -->
</div>
</el-form>
</div>
</div>
</template>
<script>
export default {
name:"Login",
data() {
return {
loginForm: {
username:'',
password:''
},
LoginFormRules:{
username:[
{ required: true, message: '请输入用户名', trigger: 'blur' },
],
password:[
{ required: true, message: '请输入密码', trigger: 'blur' },
]
}
}
},
methods:{
login(){
this.$refs['LoginFormRef'].validate(async (valid) => {
if (valid) {
let _this = this;
this.request.get("http://localhost:8080/user/login",{params:this.loginForm}).then(res=>{
// console.log(res)
if(res != null){
localStorage.setItem('access-admin',JSON.stringify(res))
//跳转登录页
// this.$router.replace({path:'/home'})
this.$router.push("/home");
}
// console.log(res)
/* if(res.code=='200'){
localStorage.setItem("user",JSON.stringify(res.data));//存储用户信息到浏览器
this.$router.push("/home");
this.$message.success("登录成功");
}else{
this.$message.error(res.msg);
} */
})
}
})
},
}
}
</script>
<style scoped>
.login_container{
background-color: #2b4b6b;
height: 100%;
}
.login_box{
width: 350px;
height: 300px;
background-color: #fff;
border-radius: 3px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%)
}
</style>
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/)
Powered by Discuz! X3.4