关于作者
金山老师:从事Java、大数据、Python职业化培训6年,项目管理、软件开发14年。欢迎添加我的微信号【jshand】,最近建了一些微信交流群,扫描下方二维码添加公众号,回复:进群
登录的逻辑
传统jsp
vuejs
基于cookie
axios中携带cookie处理起来比较麻烦,
可以使用jwt,登录之后将登录的信息,记录到h5的缓存中(自己操作),每次请求从本地存储控件取出来,可以使用jwt进行验证。
jwt
什么是JWT?
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
Session: 每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。
扩展性: 用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。
CSRF: 因为是基于cookie来进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。
基于token的鉴权机制
基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。
流程上是这样的:
- 用户使用用户名密码来请求服务器
- 服务器进行验证用户的信息
- 服务器通过验证发送给用户一个token
- 客户端存储token,并在每次请求时附送上这个token值
- 服务端验证token值,并返回数据
这个token必须要在每次请求时传递给服务端,它应该保存在请求头里, 另外,服务端要支持CORS(跨来源资源共享)
策略,一般我们在服务端这么做就可以了Access-Control-Allow-Origin: *
。
实现jwt验证用户身份
使用生成Token
- 添加依赖
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.19.1</version>
</dependency>
- 单元测试测试生成Token, 和验证Token
package com.neuedu.boot.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.junit.jupiter.api.Test;
public class JWTTest {
/**
* 模拟的是登录的 生成jwt json
*/
@Test
public void testCreate(){
String secret = "abcdef";
String jwtString = JWT.create().
withClaim("username", "root"). //设置登录的信息
sign(Algorithm.HMAC256(secret));
// admin
// eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.AwXJiXuMoJodNCq3EslfV6wVrwLIFFcaFqsAsWfITQg
// root
// eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InJvb3QifQ.c8kyOTkxOll2LM2_cEJpV2m1VtxSkkGyGET9F1WfqVE
System.out.println(jwtString);
}
@Test
public void decode(){
//admin
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.AwXJiXuMoJodNCq3EslfV6wVrwLIFFcaFqsAsWfITQg";
DecodedJWT decode = JWT.decode(token);
String username = decode.getClaim("username").asString();
System.out.println("username = " + username);
//root
token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InJvb3QifQ.c8kyOTkxOll2LM2_cEJpV2m1VtxSkkGyGET9F1WfqVE";
decode = JWT.decode(token);
username = decode.getClaim("username").asString();
System.out.println("username = " + username);
}
}
在用户登录中使用Token
controller
package com.neuedu.boot.controller;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.neuedu.boot.config.CommonResult;
import com.neuedu.boot.entity.User;
import com.neuedu.boot.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class LoginController {
@Autowired
IUserService userService;
@RequestMapping("/login")
CommonResult login(User user){
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("username",user.getUsername());
queryWrapper.eq("password",user.getPassword());
User one = userService.getOne(queryWrapper);
if(one!= null){
//使用用户身份生成jwt token ,发送个浏览器
String secret = "abcdef";
String token = JWT.create().
withClaim("userId", one.getUserId()). //设置登录用户id
withClaim("username", one.getUsername()). //设置登录的用户名
sign(Algorithm.HMAC256(secret));
return CommonResult.success(token);
}else{
return CommonResult.failed("登录失败");
}
}
}
vuejs
<template>
<div>
用户名:<input type="text" v-model="loginForm.username"/> <br/>
密码<input type="password" v-model="loginForm.password"/> <br/>
<button @click="login()">登录</button>
</div>
</template>
<script>
export default {
name:'Login',
data(){
return {
loginForm:{
username:'',
password:''
}
}
},
methods:{
//登录验证
login(){
let url = '/api/login';
this.http.get(url, (token) => {
console.log("token:",token);
alert("token:"+token)
}, this.loginForm)
}
}
}
</script>
<style>
</style>
单独的引入elementUI的组件
import { Message } from 'element-ui';
// alert("出错了:"+message)
Message.error({
message:message,
duration:2000,
offset:200
})