早期单一服务器,用户认证
缺点:单点性能压力,无法扩展
WEB应用集群,session共享模式
Tomcat广播session
分布式,SSO(single sign on)模式
业务流程图
数据库表:user_info!密码应该是加密的!
在设计密码加密方式时 一般是使用MD5+盐的方式进行加密和解密。
密码:要求用户在注册的时候 多种组合.
要求 大写 小写字母+数字+特殊字符 必须超过8位.
Web-all工程
package com.atguigu.gmall.all.controller;
/**
*
* 用户认证接口
*
*
*/
@Controller
@RequestMapping
public class PassportController {
@GetMapping("login.html")
public String login(HttpServletRequest request) {
String originUrl = request.getParameter("originUrl");
request.setAttribute("originUrl",originUrl);
return "login";
}
}
认证中心模块service-user
|
|
网关全局过滤器做了什么事???
请求过滤,过滤到用户的请求,统一鉴权,鉴别有没有访问权限.
用户登录的认证,getUserId(),根据token去redis中查用户id.返回用户id之前 还有判断IP是否一致,当前访问的ip和登录时的ip比对,如果不一致,说明用户的环境发生变化了,让他去登录.
/**
*
* 全局Filter,统一处理会员登录与外部不允许访问的服务
*
*
*/
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Autowired
private RedisTemplate redisTemplate;
private AntPathMatcher antPathMatcher = new AntPathMatcher();
//web服务配置必须登录的url
private static String[] authUrls = {"trade.html","myOrder.html","list.html"};
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
//内部服务接口,不允许外部访问
if(antPathMatcher.match("/**/inner/**", path)) {
ServerHttpResponse response = exchange.getResponse();
return out(response);
}
String userId = this.getUserId(request);
//api接口,异步请求,校验用户必须登录
if(antPathMatcher.match("/api/**/auth/**", path)) {
if(StringUtils.isEmpty(userId)) {
ServerHttpResponse response = exchange.getResponse();
return out(response);
}
}
// web服务,同步请求,校验用户必须登录
for(String url : authUrls) {
if(path.indexOf(url) != -1 && StringUtils.isEmpty(userId)) {
ServerHttpResponse response = exchange.getResponse();
//303状态码表示由于请求对应的资源存在着另一个URI,应使用GET方法定向获取请求的资源
response.setStatusCode(HttpStatus.SEE_OTHER);
response.getHeaders().set(HttpHeaders.LOCATION, "http://www.gmall.com/login.html?originUrl="+request.getURI());
return response.setComplete();
}
}
//设置网关请求头
String userTempId = this.getUserTempId(request);
if(!StringUtils.isEmpty(userId) || !StringUtils.isEmpty(userTempId)) {
if(!StringUtils.isEmpty(userId)) {
request.mutate().header("userId", userId).build();
}
if(!StringUtils.isEmpty(userTempId)) {
request.mutate().header("userTempId", userTempId).build();
}
//将现在的request 变成 exchange对象
return chain.filter(exchange.mutate().request(request).build());
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
/**
* api接口鉴权失败返回数据
* @param response
* @return
*/
private Mono out(ServerHttpResponse response) {
Result result = Result.build(null, ResultCodeEnum.LOGIN_AUTH);
byte[] bits = JSONObject.toJSONString(result).getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = response.bufferFactory().wrap(bits);
//指定编码,否则在浏览器中会中文乱码
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
return response.writeWith(Mono.just(buffer));
}
/**
* 获取当前登录用户id
* @param request
* @return
*/
private String getUserId(ServerHttpRequest request) {
String token = "";
List tokenList = request.getHeaders().get("token");
if(null != tokenList) {
token = tokenList.get(0);
} else {
MultiValueMap cookieMultiValueMap = request.getCookies();
HttpCookie cookie = cookieMultiValueMap.getFirst("token");
if(cookie != null){
token = URLDecoder.decode(cookie.getValue());
}
}
if(!StringUtils.isEmpty(token)) {
String userId = (String)redisTemplate.opsForValue().get("user:login:" + token);
return userId;
}
return "";
}
/**
* 获取当前用户临时用户id
* @param request
* @return
*/
private String getUserTempId(ServerHttpRequest request) {
String userTempId = "";
List tokenList = request.getHeaders().get("userTempId");
if(null != tokenList) {
userTempId = tokenList.get(0);
} else {
MultiValueMap cookieMultiValueMap = request.getCookies();
HttpCookie cookie = cookieMultiValueMap.getFirst("userTempId");
if(cookie != null){
userTempId = URLDecoder.decode(cookie.getValue());
}
}
return userTempId;
}
}
咱们把token放到了 cookie中,禁用了 放不进去了,后续就拿不到token了.
怎么解决的? -------给用户提示:请您启用浏览器Cookie功能或更换浏览器
从后端 能获取cookie信息,如果cookie为空.
前端 向 cookie中设置值,设置不进去,给你提示!!!
2.一顿绕
用户在A浏览器登录了 B浏览器还用登录吗?
需要登录,不同的浏览器有不同的cookie.
PC 端登录了, 客户端还用登录吗?
也是需要的,PC 和客户端 就相当于不同的浏览器.
PC: 电脑的浏览器
客户端:手机中的 APP这种
移动端:手机中的浏览器 QQ浏览器 UC浏览器 百度浏览器
3.用户登录信息多久过期?
分情况的.
PC端:可以设置 浏览器关闭就退出登录,前端能获取.
Redis中有效期和 cookie中有效期都行.
2小时 24小时 7天 都行.不能设置成 1分钟 20秒这种.
客户端: 登录信息 只要用户不清除APP的数据,登录一直有效.
4、怎么防止cookie盗用?
登录之后的token 不是存在用户浏览器的cookie中吗,用户做什么事,电商平台是保证不了的.别人获取到了 用户浏览器cookie中的数据,拿到了这个token,把token放到他自己浏览器的cookie中,访问咱们这个电商平台,就业安全问题了.
解决:
后续访问的时候 在网关 比对ip地址了,登录时的ip和后续访问的ip比较,如果不同,说明环境发生变化了,让他重新登录。
还有让token 不能见面之意。叫什么名 只要开发人员知道就行了。还可以设置一些混淆数据。
简历:
责任描述:
负责单点登录模块功能开发,包括账号密码、手机验证码、微信扫码等功能;