1.登录获取用户信息并写入token
@Override
public CommonResult loginV2(RcSysUserEntity byAccount) {
log.info("********************");
log.info("******************** account-V2:{}",byAccount.getAccount());
log.info("********************");
CommonResult userInfoV2 = getUserInfoV2(byAccount);
return userInfoV2;
}
//todo
public CommonResult getUserInfoV2(RcSysUserEntity byAccount){
List<TMenu> menus= new ArrayList<>();
String tokenResult="";
Map<String, Object> result = new HashMap<>();
try {
//获取权限信息
Optional<TRole> tRoleopt=tRoleRepository.findById(Integer.valueOf(byAccount.getRoleId()));
if(tRoleopt.isPresent()){
TRole role = tRoleopt.get();
List<TMenu> tMenus = tRoleService.querySysMenus(role.getMenuIds());
menus = tRoleService.buildMenuTreeSelect(tMenus);
}
if(null!=byAccount){
JwtPayLoad jwtPayLoad = new JwtPayLoad();
jwtPayLoad.setId(byAccount.getId());
// jwtPayLoad.setToken(byAccount.getToken());
jwtPayLoad.setAccount(byAccount.getAccount());
jwtPayLoad.setRealname(byAccount.getRealname());
jwtPayLoad.setRoleId(byAccount.getRoleId());
jwtPayLoad.setCtime(byAccount.getCtime());
jwtPayLoad.setCuser(byAccount.getCuser());
jwtPayLoad.setTel(byAccount.getTel());
jwtPayLoad.setEmail(byAccount.getEmail());
tokenResult = JwtTokenUtil.createToken(jwtPayLoad);
result.put("token", tokenResult);
result.put("permission", menus);
result.put("userInfo", byAccount);
//更新登录token
byAccount.setToken(tokenResult);
rcSysUserRepository.save(byAccount);
//写入登录日志
AsyncManager.me().execute(AsyncFactory.recordLogininfor(byAccount.getAccount(), byAccount.getAccount(), String.valueOf(byAccount.getId()), String.valueOf(byAccount.getId()), "", Constants.LOGIN_SUCCESS, "登录成功"));
return CommonResult.success(result);
}
} catch (Exception e) {
logger.info(e.getMessage());
}
return CommonResult.failed("认证失败,用户名或密码错误");
}
2.token验证获取用户信息
/**
* token验证获取用户信息
* @param token
* @return
*/
@ApiOperation(value = "token验证获取用户信息",httpMethod = "POST")
@RequestMapping(value = "tokenAuth")
@ResponseBody
public CommonResult tokenAuth(String token) {
RcSysUserEntity userInfo = null;
try {
logger.debug("token验证获取用户信息...");
RcSysUserEntity byToken = rcSysUserRepository.findByToken(token);
if (null==byToken) return CommonResult.failed("token验证获取用户信息失效!");
JwtPayLoad jwtPayLoad = JwtTokenUtil.getJwtPayLoad(token);
CommonResult tokenUser = loginService.getTokenUserV2(jwtPayLoad);
logger.debug("userInfo:{}",JSONObject.toJSONString(tokenUser.getData()));
logger.debug("token验证获取用户信息 success !");
return tokenUser;
} catch (Exception e) {
logger.debug("token验证获取用户信息 error !");
e.printStackTrace();
}
Map<String, Object> resultMap=new HashMap<>();
resultMap.put("userInfo",userInfo);
logger.debug("resultMap:{}",JSONObject.toJSONString(resultMap));
return CommonResult.success(resultMap);
}
public CommonResult getTokenUserV2(JwtPayLoad jwtPayLoad) {
Long id=jwtPayLoad.getId();
Optional<RcSysUserEntity> byAccountOpt = rcSysUserRepository.findById(id);
if (byAccountOpt.isPresent()) {
RcSysUserEntity byAccount = byAccountOpt.get();
//移除加密信息
byAccount.setSalt("");byAccount.setPassword("");
Optional<TRole> tRoleopt=tRoleRepository.findById(Integer.valueOf(byAccount.getRoleId()));
if(tRoleopt.isPresent()){
TRole role = tRoleopt.get();
List<TMenu> tMenus = tRoleService.querySysMenus(role.getMenuIds());
List<TMenu> menus = tRoleService.buildMenuTreeSelect(tMenus);
byAccount.setMenus(menus);
return CommonResult.success(byAccount);
}
}
return CommonResult.failed("token验证获取用户信息失败!");
}
@Override
public List<TMenu> querySysMenus(String menu) {
RowMapper<TMenu> rowMapper=new BeanPropertyRowMapper<>(TMenu.class);
String query=" select * from t_sys_menu where 1=1 ";
if (!menu.equals("-1")) {//-1为查全部
query+=" and find_in_set(id,'"+menu+"') ";
}
List<TMenu> list = jdbcTemplate.query(query,rowMapper);
return list;
}
/**
* 构建前端所需要下拉树结构
*
* @param menus 菜单列表
* @return 下拉树结构列表
*/
@Override
public List<TMenu> buildMenuTreeSelect(List<TMenu> menus)
{
//转换为前端data格式
List<TMenu> topNodes=menus.stream().filter(item->item.getParentId()==0).collect(Collectors.toList());
List<TMenu> nodes=new ArrayList<>();
for(TMenu item : topNodes){
TMenu combotreeVo = new TMenu();
combotreeVo.setId(item.getId());
combotreeVo.setMenuName(item.getMenuName());
combotreeVo.setParentId(item.getParentId());
combotreeVo.setMenuUrl(item.getMenuUrl());
fillSubNode(combotreeVo,menus);
if(combotreeVo.getChildren()!=null&&combotreeVo.getChildren().size()>0){
combotreeVo.setStatus(0);
}else{
combotreeVo.setStatus(1);
}
nodes.add(combotreeVo);
}
return nodes;
}
/**
* 转换
* @param pnode
* @param all
*/
public void fillSubNode(TMenu pnode, List<TMenu> all) {
List<TMenu> subNodes = all.stream().filter(item -> item.getParentId()==pnode.getId())
.collect(Collectors.toList());
if (subNodes == null || subNodes.size() == 0) {
return;
}
pnode.setChildren(new ArrayList<TMenu>());
for (TMenu item : subNodes) {
TMenu combotreeVo = new TMenu();
combotreeVo.setId(item.getId());
combotreeVo.setMenuName(item.getMenuName());
combotreeVo.setParentId(item.getParentId());
combotreeVo.setMenuUrl(item.getMenuUrl());
fillSubNode(combotreeVo, all);
if (combotreeVo.getChildren() != null && combotreeVo.getChildren().size() > 0) {
combotreeVo.setStatus(0);
} else {
combotreeVo.setStatus(1);
}
pnode.getChildren().add(combotreeVo);
}
}
3.退出
@ApiOperation(value = "退出", httpMethod = "POST")
@RequestMapping(value = "/logout")
@ResponseBody
public CommonResult logout(@RequestParam(value = "token", required = true) String token) {
RcSysUserEntity byToken = rcSysUserRepository.findByToken(token);
if (byToken == null) return CommonResult.failed("token参数异常!");
byToken.setToken("");
rcSysUserRepository.save(byToken);
return CommonResult.success("退出成功!");
}
4.角色和权限实体类
package com.zkdj.data.entity.pojo;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* @description 系统角色权限表
* @author gxf
* @date 2023-06-02
*/
@Entity
@Data
@Table(name="t_sys_menu")
@ApiModel("系统角色权限表")
public class TMenu implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@Id
@ApiModelProperty("主键")
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Integer id;
/**
* 菜单名称
*/
@ApiModelProperty("菜单名称")
@Column(name="menu_name")
private String menuName;
/**
* 父级id
*/
@ApiModelProperty("父级id")
@Column(name="parent_id")
private Integer parentId;
/**
* 菜单路径
*/
@ApiModelProperty("菜单路径")
@Column(name="menu_url")
private String menuUrl;
/**
* 创建时间
*/
@ApiModelProperty("创建时间")
@Column(name="ctime")
private String ctime;
/**
* 修改时间
*/
@ApiModelProperty("修改时间")
@Column(name="utime")
private String utime;
/**
* 状态 : 0 未启用 1 已启用
*/
@ApiModelProperty("状态 : 0 未启用 1 已启用")
@Column(name="status")
private Integer status;
/**
* 排序
*/
@ApiModelProperty("排序")
@Column(name="sort")
private Integer sort;
/**
* 是否是父级 0 不是 1是
*/
@ApiModelProperty("是否是父级 0 不是 1是")
@Column(name="is_parent")
private Integer isParent;
/** 子节点 */
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@Transient
private List<TMenu> children=new ArrayList<>();
public TMenu() {
}
public TMenu(TMenu tMenu) {
}
}
package com.zkdj.data.entity.pojo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
/**
* @description 系统角色表
* @author gxf
* @date 2023-05-29
*/
@Entity
@Data
@Table(name="t_sys_role")
@ApiModel("系统角色表")
public class TRole implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@Id
@ApiModelProperty("主键")
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Integer id;
/**
* 角色名称
*/
@ApiModelProperty("角色名称")
@Column(name="role_name")
private String roleName;
/**
* 角色标识
*/
@ApiModelProperty("角色标识")
@Column(name="role_type")
private String roleType;
/**
* 角色描述
*/
@ApiModelProperty("角色描述")
@Column(name="role_descrip")
private String roleDescrip;
/**
* 创建时间
*/
@ApiModelProperty("创建时间")
@Column(name="ctime")
private String ctime;
/**
* 修改时间
*/
@ApiModelProperty("修改时间")
@Column(name="utime")
private String utime;
/**
* 角色权限ids
*/
@ApiModelProperty("角色权限ids")
@Column(name="menu_ids")
private String menuIds;
public TRole() {
}
}
5.Jwt工具类
package com.zkdj.data.common.config.jwt.payload;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.zkdj.data.entity.model.RcSysUserEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.util.Map;
/**
* @author Administrator
*/
@Data
@ApiModel("jwt")
public class JwtPayLoad {
private static final long serialVersionUID = 1L;
@ApiModelProperty("过期时间")
private String expTime;
/**
* 主键
*/
@Id
@ApiModelProperty("主键")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 账号
*/
@ApiModelProperty("账号")
private String account;
/**
* 密码
*/
@ApiModelProperty("密码")
private String password;
/**
* 真实姓名
*/
@ApiModelProperty("真实姓名")
private String realname;
/**
* 角色id
*/
@ApiModelProperty("角色id")
private String roleId;
/**
* 盐值
*/
@ApiModelProperty("盐值")
private String salt;
/**
* 类型
*/
@ApiModelProperty("类型")
private Integer type;
/**
* 创建时间
*/
@ApiModelProperty("创建时间")
private String ctime;
/**
* 创建用户
*/
@ApiModelProperty("创建用户")
private String cuser;
/**
* 更新时间
*/
@ApiModelProperty("更新时间")
private String utime;
/**
* 令牌
*/
@ApiModelProperty("令牌")
private String token;
/**
* 电话
*/
@ApiModelProperty("电话")
private String tel;
/**
* 邮箱
*/
@ApiModelProperty("邮箱")
private String email;
/**
* 启用禁用 0禁用1启用
*/
@ApiModelProperty("启用禁用 0禁用1启用")
private Integer status;
/**
* 用户的键
*/
private String userKey;
public JwtPayLoad() {
}
public JwtPayLoad(Long id, String roleId, String account, String realname) {
this.id = id;
this.roleId = roleId;
this.account = account;
this.realname = realname;
}
public JwtPayLoad(
Long id, String roleId, String account, String realname,String expTime,String password,String salt,
Integer type,String ctime,String cuser,String utime,String token,String tel,String email,Integer status,String userKey) {
this.id = id;
this.roleId = roleId;
this.account = account;
this.realname = realname;
this.expTime = expTime;
this.password = password;
this.salt = salt;
this.type = type;
this.ctime = ctime;
this.ctime = ctime;
this.cuser = cuser;
this.utime = utime;
this.token = token;
this.tel = tel;
this.email = email;
this.status = status;
this.userKey = userKey;
}
/**
* payload转化为map形式
*
* @Date 2023/7/20 20:50
*/
public Map<String, Object> toMap() {
Map<String, Object> map = BeanUtil.beanToMap(new JwtPayLoad(id, roleId, account, realname, expTime, password, salt,
type, ctime, cuser, utime, token, tel, email, status, userKey), false, true);
return map;
}
/**
* payload转化为map形式
*
* @Date 2023/7/20 20:50
*/
public static JwtPayLoad toBean(Map<String, Object> map) {
if (map == null || map.size() == 0) {
return new JwtPayLoad();
} else {
JwtPayLoad jwtPayLoad = BeanUtil.mapToBean(map, JwtPayLoad.class, true, new CopyOptions());
return jwtPayLoad;
}
}
}
/**
* Copyright 2018-2020 stylefeng & fengshuonan (sn93@qq.com)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.zkdj.data.common.config.jwt;
import com.zkdj.data.common.config.jwt.payload.JwtPayLoad;
import com.zkdj.data.utils.UUIDUtil;
import com.zkdj.data.utils.date.DateUtil;
import io.jsonwebtoken.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Map;
/**
* <p>jwt token工具类</p>
* <pre>
* jwt的claim里一般包含以下几种数据:
* 1. iss -- token的发行者
* 2. sub -- 该JWT所面向的用户
* 3. aud -- 接收该JWT的一方
* 4. exp -- token的失效时间
* 5. nbf -- 在此时间段之前,不会被处理
* 6. iat -- jwt发布时间
* 7. jti -- jwt唯一标识,防止重复使用
* </pre>
*/
public class JwtTokenUtil {
static Integer DEFAULTSECS = 60*60*12; //默认过期时间10分钟
private final static String DEFAULT_SECRET="eyJhbGciOiJIUzUxMiJ9";
public final static String FORMAT="yyyy-MM-dd HH:mm:ss";
/**
* 生成token
*/
public static String createToken(JwtPayLoad jwtPayLoad) {
Integer expiredSeconds = DEFAULTSECS;
Date expirationDate = new Date(System.currentTimeMillis() + expiredSeconds * 1000);
if(StringUtils.isNotBlank(jwtPayLoad.getExpTime())){
expirationDate = DateUtil.getDateFormateStr(jwtPayLoad.getExpTime(),FORMAT);
}
jwtPayLoad.setExpTime(DateUtil.getDateTimeConvertStr(expirationDate,FORMAT));
return generateToken(String.valueOf(jwtPayLoad.getId()),expirationDate,jwtPayLoad.toMap());
}
/**
* 获取解析当前登录的用户token信息
* @return
*/
public static JwtPayLoad getTokenJwtPayLoadInfo() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
return JwtTokenUtil.getJwtPayLoad( request.getHeader("token"));
}
/**
* 获取jwt的payload部分
*/
public static JwtPayLoad getJwtPayLoad(String token) {
Claims claimFromToken = getClaimFromToken(token);
return JwtPayLoad.toBean(claimFromToken);
}
/**
* 解析token是否正确(true-正确, false-错误)
*/
public static Boolean checkToken(String token) {
try {
Jwts.parser().setSigningKey(DEFAULT_SECRET).parseClaimsJws(token).getBody();
return true;
} catch (JwtException e) {
return false;
}
}
/**
* 验证token是否失效
*/
public static Boolean isTokenExpired(String token) {
try {
final Date expiration = getExpirationDateFromToken(token);
if(null==expiration){
return true;
}
return expiration.before(new Date());
} catch (ExpiredJwtException expiredJwtException) {
return true;
}
}
/**
* 获取jwt失效时间
*/
public static Date getExpirationDateFromToken(String token) {
try {
return getClaimFromToken(token).getExpiration();
}catch (Exception ex){
return null;
}
}
/**
* 生成token 核心方法
*/
public static String generateToken(String userId, Date expiredDate, Map<String, Object> claims) {
final Date createdDate = new Date();
if (claims == null) {
return Jwts.builder()
.setSubject(userId)
.setIssuedAt(createdDate)
.setExpiration(expiredDate)
.signWith(SignatureAlgorithm.HS256, DEFAULT_SECRET)
.compact();
} else {
return Jwts.builder()
.setClaims(claims)
.setSubject(userId)
.setIssuedAt(createdDate)
.setExpiration(expiredDate)
.signWith(SignatureAlgorithm.HS256, DEFAULT_SECRET)
.compact();
}
}
/**
* 获取jwt的payload部分
*/
public static Claims getClaimFromToken(String token) {
if (StringUtils.isEmpty(token)) {
throw new IllegalArgumentException("token参数为空!");
}
return Jwts.parser()
.setSigningKey(DEFAULT_SECRET)
.parseClaimsJws(token)
.getBody();
}
public static void main(String[] args) {
System.out.println(UUIDUtil.get32UUID());
JwtPayLoad payLoad=new JwtPayLoad();
// payLoad.setUserId("103");
// payLoad.setExpTime("2021-12-26 23:50:50");
payLoad.setToken("eyJhbGciOiJIUzI1NiJ9.eyJleHBUaW1lIjoiMjAyMy0wNi0wMiAwMzowNjowMiIsImlkIjo0LCJhY2NvdW50IjoiemtkaiIsInJlYWxuYW1lIjoiemtkaiIsInJvbGVJZCI6IjEiLCJjdGltZSI6IjIwMjMtMDUtMzEgMTg6MDA6NDMiLCJjdXNlciI6InprZGoiLCJ0ZWwiOiIxODYxMDA4NjEwMCIsImVtYWlsIjoiMTAwMDBAcXEuY29tIiwic3ViIjoiNCIsImlhdCI6MTY4NTYwMzE2MiwiZXhwIjoxNjg1NjQ2MzYyfQ.2pI28yqsG43gRkbsUv5UyH4OqSff3w3IASmNmF7lJRo");
payLoad.setId(1L);
String jwtsecret = "";
String s = JwtTokenUtil.createToken(payLoad);
// String s = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMDMiLCJleHBUaW1lIjoiMjAyMS0xMi0xMSAwMDo1MDo1MCIsImN1c3RvbWVySWQiOm51bGwsInVzZXJOYW1lIjpudWxsLCJleHAiOjE2MzkxNTUwNTAsInVzZXJJZCI6IjEwMyIsImlhdCI6MTYzOTE1NDE0NiwiY3VzdG9tZXJOYW1lIjpudWxsfQ.WUlQlhG7DQUkMFNzm-uwD4lVCyeeNmRXY05tSeKYuEc";
// JwtPayLoad jwtPayLoad = getJwtPayLoad("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMDUiLCJleHBUaW1lIjoiMjAyMS0xMi0yNyAyMTozNzowOCIsImN1c3RvbWVySWQiOm51bGwsInVzZXJOYW1lIjoieHlneHEiLCJleHAiOjE2NDA2MTIyMjgsInVzZXJJZCI6IjEwNSIsImlhdCI6MTY0MDYxMTYyOCwiY3VzdG9tZXJOYW1lIjpudWxsfQ.8lazFHdMdQP5K-iJCGdflCBZnlNOilXVSuGcA0mU1A0");
JwtPayLoad jwtPayLoad = getJwtPayLoad(s);
System.out.println("Secret:"+ jwtPayLoad.getToken());
System.out.println("token是否正确:"+ JwtTokenUtil.checkToken(s)+jwtPayLoad.getExpTime());
System.out.println("token是否失效:"+ JwtTokenUtil.isTokenExpired(s));
System.out.println("token过期日期:"+ DateUtil.getDateTimeConvertStr(JwtTokenUtil.getExpirationDateFromToken(s),"yyyy-MM-dd HH:mm:ss"));
}
}
权限
角色
用户