前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SaaS-HRM中的TOKEN签发与验证

SaaS-HRM中的TOKEN签发与验证

作者头像
cwl_java
发布2020-01-02 11:47:15
4520
发布2020-01-02 11:47:15
举报
文章被收录于专栏:cwl_Javacwl_Java

5 HRM中的TOKEN签发与验证

5.1 什么是JWT

JSON Web Token(JWT) 是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。在Java世界中通过JJWT实现JWT创建和验证。

5.2 JWT的快速入门

5.2.1 token的创建

(1)创建maven工程,引入依赖

代码语言:javascript
复制
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.6.0</version>
</dependency>

(2)创建类CreateJwtTest,用于生成token

代码语言:javascript
复制
public class CreateJwtTest {
    public static void main(String[] args) {
        JwtBuilder builder= Jwts.builder().setId("888")
                .setSubject("小白")
                .setIssuedAt(new Date())
                .signWith(SignatureAlgorithm.HS256,"itcast");
        System.out.println( builder.compact() );
    }
}

(3)测试运行,输出如下:

代码语言:javascript
复制
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1MjM0MTM0NTh9.gq0JcOM_qCNqU_s-d_IrRytaNenesPmqAIhQpYXHZk

5.2.2 token的解析

我们刚才已经创建了token ,在web应用中这个操作是由服务端进行然后发给客户端,客户端在下次向服务端发送请求时需要携带这个token(这就好像是拿着一张门票一样),那服务端接到这个token 应该解析出token中的信息(例如用户id),根据这些信息查询数据库返回相应的结果。

创建ParseJwtTest

代码语言:javascript
复制
public class ParseJwtTest {
    public static void main(String[] args) {
        String
token="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiO
jE1MjM0MTM0NTh9.gq0J-cOM_qCNqU_s-d_IrRytaNenesPmqAIhQpYXHZk";
        Claims claims =
Jwts.parser().setSigningKey("itcast").parseClaimsJws(token).getBody();
        System.out.println("id:"+claims.getId());
        System.out.println("subject:"+claims.getSubject());
        System.out.println("IssuedAt:"+claims.getIssuedAt());
    }
}

试着将token或签名秘钥篡改一下,会发现运行时就会报错,所以解析token也就是验证token

5.2.3 自定义claims

我们刚才的例子只是存储了id和subject两个信息,如果你想存储更多的信息(例如角色)可以定义自定义claims

(1) 创建CreateJwtTest3,并存储指定的内容

代码语言:javascript
复制
public class CreateJwtTest3 {
    public static void main(String[] args) {
        //为了方便测试,我们将过期时间设置为1分钟
        long now = System.currentTimeMillis();//当前时间
        long exp = now + 1000*60;//过期时间为1分钟
        JwtBuilder builder= Jwts.builder().setId("888")
                .setSubject("小白")
                .setIssuedAt(new Date())
                .signWith(SignatureAlgorithm.HS256,"itcast")
                .setExpiration(new Date(exp))
                .claim("roles","admin") //自定义claims存储数据
                .claim("logo","logo.png");
        System.out.println( builder.compact() );
    }
}

(2) 修改ParseJwtTest,获取指定信息

代码语言:javascript
复制
public class ParseJwtTest {
    public static void main(String[] args) {
        String
compactJws="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1MjM0MT
czMjMsImV4cCI6MTUyMzQxNzM4Mywicm9sZXMiOiJhZG1pbiIsImxvZ28iOiJsb2dvLnBuZyJ9.b11p4g4rE94r
qFhcfzdJTPCORikqP_1zJ1MP8KihYTQ";
        Claims claims =
Jwts.parser().setSigningKey("itcast").parseClaimsJws(compactJws).getBody();
        System.out.println("id:"+claims.getId());
        System.out.println("subject:"+claims.getSubject());
        System.out.println("roles:"+claims.get("roles"));
        System.out.println("logo:"+claims.get("logo"));
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        System.out.println("签发时间:"+sdf.format(claims.getIssuedAt()));
        System.out.println("过期时间:"+sdf.format(claims.getExpiration()));
        System.out.println("当前时间:"+sdf.format(new Date()) );
    }
}

5.3 JWT工具类

在ihrm_common工程中创建JwtUtil工具类

代码语言:javascript
复制
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.Date;
import java.util.Map;

@Getter
@Setter
@ConfigurationProperties("jwt.config")
public class JwtUtils {
    //签名私钥
    private String key;
    //签名的失效时间
    private Long ttl;

    /**
     * 设置认证token
     *      id:登录用户id
     *      subject:登录用户名
     *
     */
    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());
        }
        jwtBuilder.setExpiration(new Date(exp));
        //4.创建token
        String token = jwtBuilder.compact();
        return token;
    }


    /**
     * 解析token字符串获取clamis
     */
    public Claims parseJwt(String token) {
        Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody();
        return claims;
    }

}

(3) 修改ihrm_common工程的application.yml, 添加配置

代码语言:javascript
复制
jwt:
 config:
    key: saas-ihrm
    ttl: 360000

5.4 登录成功签发token

(1)配置JwtUtil。修改ihrm_system工程的启动类

代码语言:javascript
复制
@Bean    
public JwtUtil jwtUtil(){    
 return new util.JwtUtil();        
}

(2)添加登录方法

代码语言:javascript
复制
 /**
     * 用户登录
     * 1.通过service根据mobile查询用户
     * 2.比较password
     * 3.生成jwt信息
     *
     */
    @RequestMapping(value="/login",method = RequestMethod.POST)
    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<>();
            map.put("companyId",user.getCompanyId());
            map.put("companyName",user.getCompanyName());
            String token = jwtUtils.createJwt(user.getId(), user.getUsername(), map);
            return new Result(ResultCode.SUCCESS,token);
       }
   }

(3)测试运行结果

在这里插入图片描述
在这里插入图片描述

使用postman验证登录返回:

代码语言:javascript
复制
{
	"success": true,
	"code": 10000,
	"message": "操作成功! ",
	 "data ":"
	eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMDYyNjYxODkxNjE4Mzc3NzI4Iiwic3ViIjoiemhhb
	mdzYW4iLCJpYXQiOjE1NDI0NjgzNzcsImNvbXBhbnlJZCI6IjEiLCJjb21wYW55TmFtZSI6IuS8oOaZuuaSreWu
	oiIsImV4cCI6MTU0MjU1NDc3N30.J - 8 uv8jOp2GMLpBwrUOksnErjA4 - DOJ_qvy7tsJbsa8 "
}

5.5 获取用户信息鉴权

需求:用户登录成功之后,会发送一个新的请求到服务端,获取用户的详细信息。获取用户信息的过程中必须登录才能,否则不能获取。

前后端约定:前端请求微服务时需要添加头信息Authorization ,内容为Bearer+空格+token

(1)添加响应值对象

代码语言:javascript
复制
@Getter
@Setter
@NoArgsConstructor
public class ProfileResult {
    private String mobile;
    private String username;
    private String company;
    private Map roles;
    public ProfileResult(User user) {
        this.mobile = user.getMobile();
        this.username = user.getUsername();
        this.company = user.getCompanyName();
        //角色数据
        Set<String> menus = new HashSet<>();
        Set<String> points = new HashSet<>();
        Set<String> apis = new HashSet<>();
        Map rolesMap = new HashMap<>();
        for (Role role : user.getRoles()) {
            for (Permission perm : role.getPermissions()) {
                String code = perm.getCode();
                if(perm.getType() == 1) {
                    menus.add(code);
               }else if(perm.getType() == 2) {
                    points.add(code);
               }else {
                    apis.add(code);
               }
           }
       }
        rolesMap.put("menus",menus);
        rolesMap.put("points",points);
        rolesMap.put("apis",points);
        this.roles = rolesMap;
   }
}

(2)添加profile方法

代码语言:javascript
复制
/**
* 获取个人信息
*/
@RequestMapping(value = "/profile", method = RequestMethod.POST)
public Result profile(HttpServletRequest request) throws Exception {
 //临时使用
    String userId = "1";
    User user = userService.findById(userId);
    return new Result(ResultCode.SUCCESS,new ProfileResult(user));
}

(3)验证token 思路:从请求中获取key为Authorization的token信息,并使用jwt验证,验证成功后获取隐藏信息。修改profile方法添加如下 代码

代码语言:javascript
复制
@RequestMapping(value = "/profile", method = RequestMethod.POST)
public Result profile(HttpServletRequest request) throws Exception {
    //请求中获取key为Authorization的头信息
      String authorization = request.getHeader("Authorization");
    if(StringUtils.isEmpty(authorization)) {
        throw new CommonException(ResultCode.UNAUTHENTICATED);
   }
    //前后端约定头信息内容以 Bearer+空格+token 形式组成
    String token = authorization.replace("Bearer ", "");
    //比较并获取claims
    Claims claims = jwtUtil.parseJWT(token);
    if(claims == null) {
        throw new CommonException(ResultCode.UNAUTHENTICATED);
   }
    String userId = claims.getId();
    User user = userService.findById(userId);
    return new Result(ResultCode.SUCCESS,new ProfileResult(user));
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 5 HRM中的TOKEN签发与验证
    • 5.1 什么是JWT
      • 5.2 JWT的快速入门
        • 5.2.1 token的创建
        • 5.2.2 token的解析
        • 5.2.3 自定义claims
      • 5.3 JWT工具类
        • 5.4 登录成功签发token
          • 5.5 获取用户信息鉴权
          相关产品与服务
          对象存储
          对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档