用户登录检验和用户鉴权是用户管理模块中重要的一环,我在网上找了一些用户登录鉴权的方法,但大多数都是通过SpringSecurity框架实现该功能。我最初也没想过使用该框架,因此自己设计了一个简便的用户登录检验以及用户鉴权模块。
1.用户登录检验
对于用户登录检验功能,我是通过拦截器和token实现该功能。具体而言,我在登录的过程中通过登录的用户名生成token,然后将生成的token存储在request的session中。后面在拦截器中拦截请求获取token,如果token为空,表示未登录,否则登录成功。
JWT生成token的工具类
public class JwtUtils {
public static String createToken(String loginName){
return Jwts.builder().
setIssuer(CommonConstants.ISS).
setSubject(loginName).
setIssuedAt(new Date()).
setExpiration(new Date(System.currentTimeMillis() + CommonConstants.EXPIRATION))
.signWith(SignatureAlgorithm.HS512, CommonConstants.SECRET)
.compact();
}
public static Date getExpiration(String token){
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(CommonConstants.SECRET).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
Date expiredTime = claims.getExpiration();
return expiredTime;
}
public static String getTokenBody(String token){
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(CommonConstants.SECRET).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
String subject = claims.getSubject();
return subject;
}
public static void main(String[] args) {
String token = createToken("xiaoku");
Date expiration = getExpiration(token);
System.out.println(expiration);
}
}
JWT工具类
登录拦截器
//使用拦截器简化之前的用户登录检验
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String tokenHeader = null;
try {
tokenHeader = request.getSession().getAttribute(CommonConstants.TOKEN_HEADER).toString();
} catch (Exception e) {
if (tokenHeader == null){
return false;
}
e.printStackTrace();
}
if(!StringUtils.isEmpty(tokenHeader) && tokenHeader.startsWith(CommonConstants.TOKEN_PREFIX)){
//处理token把开头的 "Bearer "去掉才能解析
String token = tokenHeader.replace(CommonConstants.TOKEN_PREFIX,"").trim();
if (token != null){
return true;
}
return false;
}
return false;
}
}
登录拦截器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/user-info/register", "/user-info/login");
}
}
配置类
2.用户鉴权
对于用户鉴权功能,我是通过token来控制用户访问接口的权限。具体而言,我自定义一个用户鉴权工具类,通过获取用户登录信息调用角色和menu相关API来匹配用户请求路径。如果用户请求路径包含用户所拥有的角色菜单路径则通过,反之无权限。
2.1 获取用户登录信息工具类
public class SystemThreadLocal {
//存储当前登录用户信息
private static final Map<String, UserInfo>userInfoMap = new ConcurrentHashMap();
public static void setUserInfo(UserInfo userInfo){
userInfoMap.put("userInfo", userInfo);
}
public static UserInfo getUserInfo(){
return userInfoMap.get("userInfo");
}
public static void removeUserInfo(){
userInfoMap.remove("userInfo");
}
}
用户登录信息工具类
2.2 用户鉴权工具类
//如何设计一个通用的用户鉴权呢
public class AuthUtils {
private static Logger log = LoggerFactory.getLogger(AuthUtils.class);
public static boolean checkAuth(HttpServletRequest request, RoleMenuMapper roleMenuMapper){
//1.获取用户信息
UserInfo userInfo = SystemThreadLocal.getUserInfo();
//2..截取请求路径与权限值比较吗
//request.getRequestURI()获取的是端口号后面的路径
String requestUrl = request.getRequestURI().replaceFirst("/[^/]*", "");
//3.获取数据库中该用户角色的menu路径
List<RoleMenu> roleMenuList = roleMenuMapper.selectList(new LambdaQueryWrapper<RoleMenu>().eq(RoleMenu::getRoleId, null==userInfo?null:userInfo.getRoleId()));
List<Integer> menuIds = roleMenuList.stream().map(x -> x.getMenuId()).collect(Collectors.toList());
for (Integer menuId : menuIds) {
String path = roleMenuMapper.getPath(menuId);
log.info(path);
if (requestUrl.contains(path)){
return true;
}
}
return false;
}
}
用户鉴权工具类
3.小结
以上是我做的单体项目中简要的用户登录检验和用户鉴权功能,后面会继续学习框架中的用户登录检验和用户鉴权功能,持续更新。