目录
实现方法:①:实现Filter接口②:重写init,dofilter,destroy。③:dofilter中设置跨域配置
3,用户登录的时候创建Token,放在响应头中。(使用原生的servletResponse)
4,写一个过滤器判断请求中是否存在token存在则对Token进行校验。成功则放行,不成功则返回失败。
一,浏览器的同源策略
1,同源与跨域
url: 通讯协议://IP地址:端口号/资源路径
两次请求的协议,ip,端口号都相同,我们认为两次请求的同源的
否则,不同源,需要跨域(Cors)。
2,浏览器的同源策略
浏览器发送请求,同源可以发送,不同源不能发送请求。(浏览器的安全机制)
部分html标签支持跨域script,,a,link,img等
但在项目中使用Ajax调用接口,默认是不能跨域的。
报错图片:
二,跨域处理方案(后端)
1,使用nginx服务器
2,Cors跨域资源共享,后端设置可以跨域。
三,Cors过滤器
跨域请求时复杂请求。
复杂请求跨域访问,会先发一次预检请求,请求方式时OPTIONS。
如果预检请求允许,发送真正的请求,不允许则控制台报错。
实现方法:
①:实现Filter接口
②:重写init,dofilter,destroy。
③:dofilter中设置跨域配置
HttpServletResponse resp=(HttpServletResponse)servletResponse;
HttpServletRequest req=(HttpServletRequest)servletRequest;
//设置cors:允许跨域访问
// 预检请求方式是:OPTIONS
// 1\允许哪些域可以访问我
resp.setHeader("Access-Control-Allow-Origin","*");
// resp.setHeader("Access-Control-Allow-Origin","http://localhost:8080");
// resp.setHeader("Access-Control-Allow-Origin",req.getHeader("Origin"));
// 2、允许哪些请求方式
resp.setHeader("Access-Control-Allow-Methods","get,post,OPTIONS");
// 3、请求头中包含
resp.setHeader("Access-Control-Allow-Headers","token");
// 4、跨域是否允许携带cookie
resp.setHeader("Access-Control-Allow-Credentials","true");
// 5、预检请求的时间间隔
resp.setHeader("Access-Control-Max-Age","3600");
// 6、 可以向客户端浏览器暴露哪些请求头
resp.setHeader("Access-Control-Expose-Headers", "token");
// 将请求交给目标资源
filterChain.doFilter(req, resp);
跨域不能携带cookie和session会话跟踪。所以使用token。
四,Jwt(Token)
介绍:JWT就是一个带有用户信息的加密字符串。JWT可以使用密钥(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。通常用于用户登录。
Jwt组成:Header(头部),Payload(载荷),Signature(签名)三部分组成,中间以点分隔。
类库:进入官方-----libraries----Filterby(选择Java)-----自己选择下载
Token的使用:Maven项目
1,导入依赖(版本自己选择)
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.11.0</version>
</dependency>
2,编写工具类
/**
* 用于生成和解析JWT
*/
public class JWTUtils {
/**
* 声明一个秘钥
*/
private static final String SECRET = "leige";
/**
* 生成JWT
*
* @param userId 用户编号
* @param username 用户名
* @param auth 用户权限
*/
public String createToken(Integer userId, String username, List<String> auth) {
//得到当前的系统时间
Date currentDate = new Date();
//根据当前时间计算出过期时间 定死为5分钟
Date expTime = new Date(currentDate.getTime() + (1000 * 60 * 5));
//组装头数据
Map<String, Object> header = new HashMap<>();
header.put("alg", "HS256");
header.put("typ", "JWT");
return JWT.create()
.withHeader(header) //头
.withClaim("userId", userId) //自定义数据
.withClaim("username", username) //自定义数据
.withClaim("auth", auth) //自定义数据
.withIssuedAt(currentDate) //创建时间
.withExpiresAt(expTime)//过期时间
.sign(Algorithm.HMAC256(SECRET));
}
/**
* 验证JWT并解析
*
* @param token 要验证的jwt的字符串
*/
public static Boolean verifyToken(String token) {
try{
// 使用秘钥创建一个解析对象
JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256(SECRET)).build();
//验证JWT
DecodedJWT decodedJWT = jwtVerifier.verify(token);
return true;
}catch (TokenExpiredException e){
e.printStackTrace();
}
return false;
}
/**
* 获取JWT里面相前的用户编号
*/
public Integer getUserId(String token){
try{
// 使用秘钥创建一个解析对象
JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256(SECRET)).build();
//验证JWT
DecodedJWT decodedJWT = jwtVerifier.verify(token);
Claim userId = decodedJWT.getClaim("userId");
return userId.asInt();
}catch (TokenExpiredException e){
e.printStackTrace();
}
return null;
}
/**
* 获取JWT里面相前的用户名
*/
public static String getUsername(String token){
try{
// 使用秘钥创建一个解析对象
JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256(SECRET)).build();
//验证JWT
DecodedJWT decodedJWT = jwtVerifier.verify(token);
Claim username = decodedJWT.getClaim("username");
return username.asString();
}catch (TokenExpiredException e){
e.printStackTrace();
}
return null;
}
/**
* 获取JWT里面相前权限
*/
public List<String> getAuth(String token){
try{
// 使用秘钥创建一个解析对象
JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256(SECRET)).build();
//验证JWT
DecodedJWT decodedJWT = jwtVerifier.verify(token);
Claim auth = decodedJWT.getClaim("auth");
return auth.asList(String.class);
}catch (TokenExpiredException e){
e.printStackTrace();
}
return null;
}
}
3,用户登录的时候创建Token,放在响应头中。(使用原生的servletResponse)
@RequestMapping("/login")
public R loginUsers(String uname, String upassword, HttpServletResponse resp) throws UnsupportedEncodingException {
Users user = service.Userlogin(uname);
if (!user.getUname().equals(uname)){
return R.loginfail();
}else if(!user.getUpassword().equals(upassword)){
return R.fali("用户密码错误,请重新输入");
}else {
String token = TokenUtil.toToken();
//响应token
resp.setHeader("token",token);
return R.sussce("登录成功");
}
}
4,写一个过滤器判断请求中是否存在token
存在则对Token进行校验。成功则放行,不成功则返回失败。
// 获取请求头中的token
String token = req.getHeader("token");
// token为空或校验失败
if (token==null || !TokenUtil.validateJWT(token)){
// 没有登录
PrintWriter out = resp.getWriter();
ObjectMapper mapper = new ObjectMapper();
out.write(mapper.writeValueAsString(R.loginfail()));
out.close();
}else {
// 放行
filterChain.doFilter(req,resp);
}