简介
上篇文章讲了下 JWT 的简单使用,了解了如何创建及解析 token,这篇文章说下如何封装一个 JWT 工具类及如何在项目中去使用它做用户的鉴权。
一、JWT工具类
- 在项目中创建 JwtUtils 工具类,加上
@Component
注解将此工具类纳入spring容器中管理,@Getter
和@Setter
简化代码。
@Component
@Getter
@Setter
@ConfigurationProperties("jwt.config")
public class JwtUtils {
//签名私钥
private String key;
//签名的失效时间
private Long ttl;
/**
* 设置认证token
* id:登录用户id
* subject:登录用户名
* map:自定义的数据
*/
public String createJwt(String id, String name, Map<String,Object> map) {
//1.设置失效时间(毫秒)
long now = System.currentTimeMillis();
long exp = now + ttl;
//2.创建jwtBuilder
JwtBuilder jwtBuilder = Jwts.builder().setId(id).setSubject(name)
.setIssuedAt(new Date())
.signWith(SignatureAlgorithm.HS256, key);
//3.根据map设置claims
for(Map.Entry<String,Object> entry : map.entrySet()) {
jwtBuilder.claim(entry.getKey(),entry.getValue());
}
//4.设置token过期时间
jwtBuilder.setExpiration(new Date(exp));
//5.创建token
String token = jwtBuilder.compact();
return token;
}
/**
* 解析token字符串获取clamis
*/
public Claims parseJwt(String token) {
Claims claims = null;
try{
claims = Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody();
}catch (Exception e){
e.printStackTrace();
}
return claims;
}
}
- 修改项目的 application.yml, 添加配置
#JWT配置
jwt:
config:
key: jwt-key #token私匙,自定义就可以
ttl: 360000 #token过期时间,单位毫秒,这里是6分钟
用户登录接口
- 定义返回码枚举类
/** 公共的返回码 返回码code: 成功:10000 失败:10001 未登录:10002 未授权:10003 抛出异常:99999 */
public enum ResultCode {
SUCCESS(true, 10000, "操作成功!"),
// ---系统错误返回码-----
FAIL(false, 10001, "操作失败"),
UNAUTHENTICATED(false, 10002, "您还未登录"),
UNAUTHORISE(false, 10003, "权限不足"),
SERVER_ERROR(false, 99999, "抱歉,系统繁忙,请稍后重试!"),
// ---用户操作返回码 2xxxx----
MOBILEORPASSWORDERROR(false, 20001, "用户名或密码错误");
// ---企业操作返回码 3xxxx----
// ---权限操作返回码----
// ---其他操作返回码----
// 操作是否成功
boolean success;
// 操作代码
int code;
// 提示信息
String message;
ResultCode(boolean success, int code, String message) {
this.success = success;
this.code = code;
this.message = message;
}
public boolean getSuccess() {
return success;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}
- 定义返回体
/**
* 数据响应对象 { success :是否成功 code :返回码 message :返回信息 data :返回数据
*/
@Data
@NoArgsConstructor
public class Result {
private boolean success; // 是否成功
private Integer code; // 返回码
private String message; // 返回信息
private Object data; // 返回数据
public Result(ResultCode code) {
this.success = code.success;
this.code = code.code;
this.message = code.message;
}
public Result(ResultCode code, Object data) {
this.success = code.success;
this.code = code.code;
this.message = code.message;
this.data = data;
}
public Result(Integer code, String message, boolean success) {
this.code = code;
this.message = message;
this.success = success;
}
public static Result SUCCESS() {
return new Result(ResultCode.SUCCESS);
}
public static Result ERROR() {
return new Result(ResultCode.SERVER_ERROR);
}
public static Result FAIL() {
return new Result(ResultCode.FAIL);
}
}
- 定义用户登录接口
@RestController
public class UserController {
@Autowired private JwtUtils jwtUtils;
@Autowired private UserService userService;
/** * 用户登录 * 1.通过service根据mobile查询用户 * 2.比较password * 3.生成jwt信息 * */
@PostMapping(value = "/login")
public Result login(@RequestBody Map<String, String> loginMap) {
String mobile = loginMap.get("mobile");
String password = loginMap.get("password");
// 查询用户
User user = userService.findByMobile(mobile);
// 登录失败
if (user == null || !user.getPassword().equals(password)) {
return new Result(ResultCode.MOBILEORPASSWORDERROR);;
} else {
// 登录成功
Map<String, Object> map = new HashMap<>(16);
map.put("companyId", user.getCompanyId());
map.put("companyName", user.getCompanyName());
//登录成功,签发token
String token = jwtUtils.createJwt(user.getId(), user.getUsername(), map);
return new Result(ResultCode.SUCCESS,token);
}
}
}
三、用户信息鉴权
用户登录成功之后,会发送一个新的请求到服务端,获取用户的详细信息。获取用户信息的过程中必须登录才能,否则不能获取。
前后端约定:前端请求微服务时需要添加头信息Authorization ,内容为Bearer+空格+token
- 定义用户信息响应体
@Setter
@Getter
public class ProfileResult {
private String mobile;
private String username;
private String company;
private Map<String,Object> roles = new HashMap<>(16);
public ProfileResult(User user) {
this.mobile = user.getMobile();
this.username = user.getUsername();
this.company = user.getCompanyName();
//角色数据
Set<Role> roles = user.getRoles();
Set<String> menus = new HashSet<>();
Set<String> points = new HashSet<>();
Set<String> apis = new HashSet<>();
for (Role role : roles) {
Set<Permission> perms = role.getPermissions();
for (Permission perm : perms) {
String code = perm.getCode();
if(perm.getType() == 1) {
menus.add(code);
}else if(perm.getType() == 2) {
points.add(code);
}else {
apis.add(code);
}
}
}
this.roles.put("menus",menus);
this.roles.put("points",points);
this.roles.put("apis",apis);
}
}
- 用户信息鉴权接口,获取用户信息
/**
* 用户登录成功之后,获取用户信息
* 1.获取用户id
* 2.根据用户id查询用户
* 3.构建返回值对象
* 4.响应
*/
@PostMapping(value="/profile")
public Result profile(HttpServletRequest request) throws Exception {
/**
* 从请求头信息中获取token数据
* 1.获取请求头信息:名称=Authorization
* 2.替换Bearer+空格
* 3.解析token
* 4.获取clamis
*/
//1.获取请求头信息:名称=Authorization
String authorization = request.getHeader("Authorization");
if(StringUtils.isEmpty(authorization)) {
throw new CommonException(ResultCode.UNAUTHENTICATED);
}
//2.替换Bearer+空格
String token = authorization.replace("Bearer ","");
//3.解析token
Claims claims = jwtUtils.parseJwt(token);
String userid = claims.getId();
//查询用户
User user = userService.findById(userid);
//构造用户信息响应体数据
ProfileResult result = new ProfileResult(user);
return new Result(ResultCode.SUCCESS,result);
}