哪个网站有免费空间linux建站和wordpress
目录
定义:
实现思路:
功能实现:
定义拦截器并注册
定义:
因为我们目前的项目是前后端分离的项目,我们可以通过用户分配的资源来确定,当前登录人是否有权限访问该资源
实现思路:
可以看到,我们在登录功能补充了这些逻辑获取用户资源列表,获取白名单列表,将Jwt存储到Redis中,在拦截器中从redis中取出数据,验证当前用户是否拥有使用

• 什么是白名单url?
○ 白名单url是指任意用户都可以访问的系统资源(接口路径)
• 系统中哪些资源需要进行控制?
○ 在资源管理中,菜单中有定义按钮,而按钮对应的就是接口路径,如果用户分配了菜单,并且分配了按钮,则可以正常访问
○ 如果用户分配了菜单,但是没有分配按钮,则没有权限访问
○ 其中按钮的路径与白名单的路径是互斥的

功能实现:
功能实现的第一步,我们要知道我们要什么,我们要从通过用户表查询到该用户在资源表中对应资源列表

对于Mappper层,我们首先要知道我们要什么,在数据库中通过控制台对数据进行查询,查询成功后我们在idea中编写对应的mapper层和xml查询语句


在service层,前文我们也分析过,补充了这些逻辑

package com.zzyl.service.impl;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.json.JSONUtil;
import com.zzyl.constant.CacheConstants;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.LoginDto;
import com.zzyl.entity.Resource;
import com.zzyl.entity.User;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.mapper.UserMapper;
import com.zzyl.properties.JwtTokenManagerProperties;
import com.zzyl.properties.SecurityConfigProperties;
import com.zzyl.service.LoginService;
import com.zzyl.utils.JwtUtil;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;@Service
public class LoginServiceImpl implements LoginService {@Autowiredprivate UserMapper userMapper;@Autowiredprivate JwtTokenManagerProperties jwtTokenManagerProperties;@Autowiredprivate ResourceMapper resourceMapper;@Autowiredprivate SecurityConfigProperties securityConfigProperties;@Autowiredprivate StringRedisTemplate redisTemplate;/*** 用户登录* @param loginDto* @return*/@Overridepublic UserVo login(LoginDto loginDto) {//根据用户名查询用户User user = userMapper.selectByUsername(loginDto.getUsername());//判断用户是否为空if(ObjectUtil.isEmpty(user)){throw new BaseException(BasicEnum.LOGIN_FAIL);}//判断用户是否被禁用if(user.getDataState().equals(SuperConstant.DATA_STATE_1)){throw new BaseException(BasicEnum.ACCOUNT_DISABLED);}//判断密码是否正确if(!BCrypt.checkpw(loginDto.getPassword(), user.getPassword())){throw new BaseException(BasicEnum.INCORRECT_PASSWORD);}//对象转换UserVo userVo = BeanUtil.toBean(user, UserVo.class);//密码脱敏userVo.setPassword("");//获取当前用户对应的资源列表List<Resource> resourceList = resourceMapper.selectListByUserId(user.getId());;//取出request_pathList<String> urlList = resourceList.stream().map(Resource::getRequestPath).collect(Collectors.toList());//获取白名单url列表List<String> publicAccessUrls = securityConfigProperties.getPublicAccessUrls();urlList.addAll(publicAccessUrls);//根据用户生成JWTMap<String,Object> claims = new HashMap<>();claims.put("currentUser", JSONUtil.toJsonStr(userVo));String token = JwtUtil.createJWT(jwtTokenManagerProperties.getBase64EncodedSecretKey(), jwtTokenManagerProperties.getTtl(),claims);//设置过期时间int ttl = jwtTokenManagerProperties.getTtl() / 1000;//存储到redisredisTemplate.opsForValue().set(CacheConstants.PUBLIC_ACCESS_URLS + userVo.getId(), JSONUtil.toJsonStr(urlList), ttl, TimeUnit.SECONDS);userVo.setUserToken(token);return userVo;}
}
对于白名单,我们将它写入到配置文件中
这里因为白名单的路径太多了,我们另写了一个yml配置文件,在Spring项目启动后会合并

以及在对应的common模块中加入了配置类

定义拦截器并注册
inteceptor拦截器是Spring框架的拦截器,在请求进入Controller前和数据从Controller层出来返回给前端这段逻辑从前端获取token解析token,并获取用户数据,从Redis中取出该用户对应能够访问的Url列表,与当前请求url进行对比得出能否访问的结论

package com.zzyl.intercept;import cn.hutool.json.JSONUtil;
import com.zzyl.constant.CacheConstants;
import com.zzyl.constant.Constants;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.properties.JwtTokenManagerProperties;
import com.zzyl.utils.JwtUtil;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.utils.StringUtils;
import com.zzyl.utils.UserThreadLocal;
import com.zzyl.vo.UserVo;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;@Component
public class UserTokenInterceptor implements HandlerInterceptor {@Autowiredprivate JwtTokenManagerProperties jwtTokenManagerProperties;@Autowiredprivate RedisTemplate<String,String> redisTemplate;private AntPathMatcher antPathMatcher = new AntPathMatcher();@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//判断当前请求是否是handler()if(!(handler instanceof HandlerMethod)){return true;}//获取tokenString token = request.getHeader(Constants.USER_TOKEN);//token是否为空if(StringUtils.isEmpty(token)){throw new BaseException(BasicEnum.LOGIN_LOSE_EFFICACY);}//解析tokenClaims claims = JwtUtil.parseJWT(jwtTokenManagerProperties.getBase64EncodedSecretKey(), token);if(ObjectUtil.isEmpty(claims)){throw new BaseException(BasicEnum.LOGIN_LOSE_EFFICACY);}//获取用户数据String userJson = String.valueOf(claims.get("currentUser"));//获取用户数据UserVo userVo = JSONUtil.toBean(userJson, UserVo.class);//从redis获取url列表String key = CacheConstants.PUBLIC_ACCESS_URLS+userVo.getId();String urlJson = redisTemplate.opsForValue().get(key);List<String> urlList = null;if(StringUtils.isNotEmpty(urlJson)){urlList = JSONUtil.toList(urlJson, String.class);}//获取当前请求路径String targetUrl = request.getMethod() + request.getRequestURI();//匹配当前路径是否在urllist集合中for (String url : urlList) {if(antPathMatcher.match(url,targetUrl)){//存储到当前线程中UserThreadLocal.setSubject(userJson);return true;}}throw new BaseException(BasicEnum.SECURITY_ACCESSDENIED_FAIL);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {UserThreadLocal.removeSubject();}
}
由于项目中有很多的请求都不需要使用安全框架进行过滤,如登录相关的接口、swagger、小程序端的接口
所以,我们需要在上述配置中添加放行的url列表,为了更方便的维护,我们可以放到application.yml文件中
如下:

这些忽略的url不需要登录也不需要鉴权,不会走拦截器的逻辑
完善SecurityConfigProperties 配置文件:
package com.zzyl.properties;import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;import java.util.ArrayList;
import java.util.List;/*** 忽略配置及跨域*/
@Slf4j
@Data
@ConfigurationProperties(prefix = "zzyl.framework.security")
@Configuration
public class SecurityConfigProperties {/*** 默认密码*/String defaulePassword ;List<String> publicAccessUrls = new ArrayList<>();List<String> ignoreUrl = new ArrayList<>();}
找到WebMvcConfig类,注册上我们刚刚编写的这个新的拦截器,将UserTokenInterceptor拦截器加入并除去SecurityConfigProperties中的路径

