Java SpringCloud 分布式鉴权 --Cookie携带token
该鉴权思路为,前端登入账号如果账号密码正确后端返回前端jwt字符串,并且通过JavaScript讲返回的jwt保存到cookie里。以后每次通过网关进行访问都会经过网关拦截器判断是否登入、jwt是否过期。如果过期或者没有登入则跳转登入页面。
这是我第一次发布博文,谢谢大家支持,如果我的文章不够详细,联系我的邮箱y51288033@outlook.com 我远程帮助你
下期更新:Java SpringCloud 分布式鉴权 --使用Shiro安全框架共享Session方法
JWT工具类
package com.dazuizui.api.utils;
import com.dazuizui.api.pojo.User;
import com.sun.javafx.scene.traversal.Algorithm;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @author 哇塞大嘴好帅
* @Time 2020/8/7 21:54
* @Text 该工具类负责生成和解析JWT
*/
public class JwtUtil {
/**
* 生成或解析令牌时候所需要的密钥
*/
private final static String JWTKey = "您的密钥";
/**
* 生成密文
* @return
*/
public static String createJWT(User user){
//构建jwt令牌
JwtBuilder builder = Jwts.builder();
builder.setIssuer("颁发者"); //颁发者
builder.setIssuedAt(new Date()); //颁发时间
builder.setSubject("主题"); //主题
builder.setExpiration(new Date(System.currentTimeMillis()+3600000)); //过期时间 设置3600秒
//自定义信息 自定义载荷
Map<String,Object> map = new HashMap<>();
map.put("username","登入者昵称");
builder.addClaims(map); //添加载荷
builder.signWith(SignatureAlgorithm.HS256,JWTKey); //1.算法 2.密钥
//生成密文
String jstString = builder.compact();
return jstString;
}
/**
* 解析密钥
* @param token 传入的token 并且从token解析的数据获取登入的用户名
* @return
*/
public static String analysisJWT(String token){
System.out.println("获取到的"+token);
Claims body = Jwts.parser()
//密钥
.setSigningKey(JWTKey)
//要解析的令牌
.parseClaimsJws(token)
//获取解析后的数据
.getBody();
System.out.println(body.get("username"));
return (String) body.get("username");
}
}
网关编写 采用Gateway网关
<!--网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
使用网关的Filter做鉴权
package com.dazuizui.gateway.filter;
import com.dazuizui.api.utils.JwtUtil;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* @author 哇塞大嘴好帅
* @blog www.dazuizui.com
* @Time 2020/7/11 21:05
* @Text DaZui_Blog项目的网关拦截器
*/
@Component
public class AuthFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//跳转登入界面验证工具,如果为假就不跳转登入页面 如果跳转就跳转
boolean goUrlHuser = false;
//获取cookie
MultiValueMap<String, HttpCookie> cookies = exchange.getRequest().getCookies();
//获取url
String url = exchange.getRequest().getURI().toString();
//如果访问的url存在/huser/就需要鉴权
if (url.contains("/huser/")){
//存放token的值
String tokenstr = "";
//判断是否存在token记录
if (cookies.getFirst("token") == null){
System.out.println("[Filter] : 不存在token");
goUrlHuser = true;
}else{
HttpCookie tokencookie = cookies.getFirst("token");
tokenstr = tokencookie.getValue();
System.out.println("接收到的token"+tokenstr);
}
//判断用户token是否过期或者恶意登入
if (!goUrlHuser){
String userdate = null;
try {
userdate = JwtUtil.analysisJWT(tokenstr);
} catch (Exception e) {
System.out.println("用户可能存在恶意登入或者登入token过期");
goUrlHuser = true;
}
}
//如果没有登入或者token存在问题跳转登入页面
if (goUrlHuser){
//重定向到
url = "http://127.0.0.1:8080/hlogin/index.html";
System.out.println(url);
exchange.getResponse().setStatusCode(HttpStatus.SEE_OTHER);
exchange.getResponse().getHeaders().set(HttpHeaders.LOCATION,url);
return exchange.getResponse().setComplete();
}
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -10;
}
}
校验账号密码是否正确
/**
* 判断账号密码是否正确,如果正确跳转到重定向的界面,如果不正确跳转登入界面重新登入
* @param username 账号
* @param password 密码
* @return
*/
@CrossOrigin
@PostMapping(value="/userlogin/ShiroLogin")
@ResponseBody
public String logim(@RequestParam("username") String username,@RequestParam("password") String password, HttpSession session, HttpServletResponse response) throws IOException {
//判断账号密码是否正确
if (username.equals("root") && password.equals("admin")) {
String jwtstring = JwtUtil.createJWT(user);
return jwtstring;
}else{
return "false";
}
}
前端部分
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">
<meta http-equiv="X-UA-COMPATIBLE" content="IE=edge,chrome=1"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>登入</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.0/dist/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="http://175.24.118.135:8080/static/dazuiblog/userlogin.css">
</head>
<body class="text-center">
<div id="Sing" class="main animated zoomIn" v-cloak>
<form v-on:submit.prevent="submit()">
<img class="mb-4" src="http://175.24.118.135:8080/static/asserts/img/Logo/Logo.png" alt="" width="250" height="250">
<h1 class="h3 mb-3 font-weight-normal"></h1>
<label class="sr-only">Username</label>
<input type="text" class="form-control" placeholder="username" required="" autofocus="" id="username" name="username" v-model="userlogin.username">
<label class="sr-only">Password</label>
<input type="password" class="form-control" placeholder="password" required="" id="password" name="password" v-model="userlogin.password">
<button class="btn btn-lg btn-primary btn-block" type="submit" id="sub" v-bind:hidden="formbutton" style="width:300px;height: 50px;"> 登入</button>
<button class="btn btn-primary" type="button" disabled v-bind:hidden="!formbutton" style="width:300px;height: 50px;">
<span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true"></span>
正在登入中......
</button>
还没有账号?<a href="http://175.24.118.135:8080/hlogin/enroll.html">点击我注册</a>
<p class="mt-5 mb-3 text-muted">© 2020 - 2020 大嘴开发团队</p>
</form>
</div>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="http://175.24.118.135:8080/static/dazuiblog/js/dazuiblog.js"></script>
<script src="https://cdn.bootcss.com/qs/6.5.2/qs.min.js"></script>
<script>
var vm = new Vue({
el: "#Sing",
data: {
formbutton: false,
userlogin:{
username: null,
password: null,
},
msg: null,
},
methods: {
//表单提交
submit() {
//更换按钮为不可点击
this.formbutton = true;
var qs = Qs;
var formData = new FormData(event.target);
axios.post("http://127.0.0.1:8080/userlogin/ShiroLogin",qs.stringify({
username:this.userlogin.username,
password:this.userlogin.password,
})).then(function (response) {
//登入成功
if (response.data != false){
//将登入信息存入cookie
setCookie("token",response.data);
window.location.href="http://127.0.0.1:8080/hblog/blogindex.html";
} else{
//登入失败
alert("您输入的账号或者密码错误");
window.location.href="http://127.0.0.1:8080/hlogin/index.html";
}
})
}
}
});
</script>
</body>
</html>
js脚本语句
//设置cookie
function setCookie (name, value) {
if (value) {
var Days = 365
var exp = new Date()
exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000)
document.cookie = name + '=' + escape(value) + ';expires=' + exp.toGMTString()+"; path=/";
}
}
//获取cookie
function getCookie(NameOfCookie) {
if (document.cookie.length > 0) {
begin = document.cookie.indexOf(NameOfCookie + "=");
if (begin !== -1) {
begin += NameOfCookie.length + 1;
end = document.cookie.indexOf(";", begin);
if (end === -1) end = document.cookie.length;
return unescape(document.cookie.substring(begin, end));
}
}
return null;
}
//获取url参数
function getQueryVariable(variable)
{
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if(pair[0] == variable){return pair[1];}
}
return(false);
}