jwt作登入认证

1 Jwt组成
一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。
在这里插入图片描述
2.1 头部(Header)
头部用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。这也可以
被表示成一个JSON对象。

{“typ”:“JWT”,“alg”:“HS256”}

在头部指明了签名算法是HS256算法。 我们进行BASE64编
码http://base64.xpcha.com/,编码后的字符串如下:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2

的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符。三个字节有24

个比特,对应于4个Base64单元,即3个字节需要用4个可打印字符来表示。JDK 中

提供了非常方便的 BASE64EncoderBASE64Decoder,用它们可以非常方便的
完成基于 BASE64 的编码和解码

2.2 载荷(playload)
载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分
(1)标准中注册的声明(建议但不强制使用)

(2)公共的声明
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.
但不建议添加敏感信息,因为该部分在客户端可解密.

(3)私有的声明
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64
是对称解密的,意味着该部分信息可以归类为明文信息。

定义一个payload:

{"sub":"1234567890","name":"John Doe","admin":true}

然后将其进行base64编码,得到Jwt的第二部分。

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

2.3 签证(signature)
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:

header (base64后的)
payload (base64后的)
secret

这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符
串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第
三部分。

TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6I
kpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7Hg
Q

注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用
来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流
露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。

3 token工具类

<dependency>
      <groupId>com.auth0</groupId>
      <artifactId>java-jwt</artifactId>
      <version>3.8.2</version>
</dependency>

编写token工具java代码

public class TokenUtils {

    //设置过期时间
    private static final long EXPIRE_DATE=30*60*100000;
    //token秘钥
    private static final String TOKEN_SECRET = "qianggezainaliwyywyasdaDQWCWQ%5ASAACACAssda";

    /**
     * 生成token
     * @param username
     * @param name
     * @param phone
     * @param url
     * @param address
     * @return
     */
    public static String token (String name,String phone,String image){

        String token = "";
        try {
            //过期时间
            Date date = new Date(System.currentTimeMillis()+EXPIRE_DATE);
            //秘钥及加密算法
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            //设置头部信息
            Map<String,Object> header = new HashMap<>();
            header.put("typ","JWT");
            header.put("alg","HS256");
            //携带username,password信息,生成签名
            token = JWT.create()
                    .withHeader(header)
                    .withClaim("name",name)
                    .withClaim("phone",phone)
                    .withClaim("image",image)
                    .withExpiresAt(date)
                    .sign(algorithm);
        }catch (Exception e){
            e.printStackTrace();
            return  null;
        }
        return token;
    }

    /**
     * 校验
     * @param token
     * @return
     */
    public static boolean verify(String token){
        /**
         * @desc   验证token,通过返回true
         * @params [token]需要校验的串
         **/
        try {
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return  false;
        }
    }



    public static void main(String[] args) {

        String token = token("wyy","110","12321");
        //System.out.println(token);
        //eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpbWFnZSI6IjEyMzIxIiwicGhvbmUiOiIxMTAiLCJuYW1lIjoid3l5IiwiZXhwIjoxNjA3MjI3MDcyfQ.hsw2M6tHUAJXKWv0xNNB9iOK-_sLnanfcGYP29NoS_4


        boolean b = verify("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpbWFnZSI6IjEyMzIxIiwicGhvbmUiOiIxMTAiLCJuYW1lIjoid3l5IiwiZXhwIjoxNjA3MjI3MDcyfQ.hsw2M6tHUAJXKWv0xNNB9iOK-_sLnanfcGYP29NoS_4");
        System.out.println(b);
    }

}

4 .登录业务代码
service登入业务代码

@Override
    public String login(HttpServletRequest request, String phone, String code) throws CustomerException {

        if( request.getSession().getAttribute("employee")!=null){
            throw new CustomerException("用户已经登录!");
        }

        Employee employee=employeeDao.findEmployeeByPhone(phone);
        if (employee==null) {
            throw new CustomerException("账户信息不存在!");
        }

        //比对验证码
       String serverCode= (String) request.getSession().getAttribute("code");
        if(serverCode==null){
            throw new CustomerException("验证码失效!");
        }
        if(!serverCode.equals(code)){
            throw new CustomerException("验证码输入错误!");
        }

        //服务器生成jwt令牌   重点在这!!!
     
>   String token = TokenUtils.token(employee.getName(),
> employee.getPhone(), employee.getImage());
> 
> 
>         return token;

    }
}

controller层处理登入的代码

//处理登录
    private void to(HttpServletRequest req, HttpServletResponse resp) {
        Result result=null;
        try {
            String code = req.getParameter("code");
            String phone = req.getParameter("phone");
            //TODO 校验
            
            //重点部分!!!!
          

>   String token = employeeService.login(req, phone, code);
>             result = new Result(0, "", null, token);

        }
       catch (CustomerException e){
                result = new Result(500002, e.getMessage(), null, null);
        }catch (Exception e){
                result = new Result(50000, "系统开小差了 !", null, null);
        }
        ResponseUtils.responseJson(JsonUtils.objectToJson(result), resp);
    }

5 认证代码
在这里插入图片描述

编写当前线程的工具类

public class UserThreadLocal {

    private static ThreadLocal<Map> tl=new ThreadLocal<Map>();

    /**
     * 绑定用户信息到当前线程
     * @param map
     */
    public static void setUser(Map map){
        tl.set(map);
    }

    /**
     * 获取当前线程绑定的用户信息
     * @return
     */
    public static Map getUser(){
       return tl.get();
    }

    /**
     * 移除当前线程绑定的用户信息
     */
    public static void removeUser(){
        tl.remove();
    }

}

过滤器代码

@WebFilter(filterName="loginFilter",value = "/*")
public class LoginFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request= (HttpServletRequest) req;
        HttpServletResponse response= (HttpServletResponse) res;

        //登录相关接口放行

        //获取客户端请求的资源路径
        String uri = request.getRequestURI();

        System.out.println(uri+"-------------");

        //不拦截的资源
        if(uri.contains("/crm/login")){

            //直接访问 放行
            chain.doFilter(request,response);

            return;
        }

       //!!!!!!!!!!   重点   jwt认证代码

>  //必须要认证的资源
>         //先从请求参数获取token
>         String token=request.getParameter("token");
>         if(token==null||token.trim().equals("")){
>             token=request.getHeader("token");
>             if(token==null||token.trim().equals("")) {
>                 Result result = new Result(50003, "用户没有登录,不允许访问!", null, null);
>                 ResponseUtils.responseJson(JsonUtils.objectToJson(result), response);
>                 return;
>             }
>         }
> 
>         //校验jwt令牌是否合法,是否过期
>         if(!TokenUtils.verify(token)){
>             //token不合法
>             Result result = new Result(50003, "用户没有登录,不允许访问!", null, null);
>             ResponseUtils.responseJson(JsonUtils.objectToJson(result), response);
>             return;
>         }
> 
> 
>         //后面在servlet的业务代码中需要获取当前用户的登录信息?
>         //解密载荷的信息
>         DecodedJWT jwt = JWT.decode(token);
>         Map<String, Claim> claims = jwt.getClaims();//获取载荷信息  用户登录的信息
> 
>         //绑定到当前线程
>         UserThreadLocal.setUser(claims);
> 
> 
>         //放行
>         chain.doFilter(request,response);
> 
> 
>         //移除当前线程绑定的用户信息
>         UserThreadLocal.removeUser();

    }

    @Override
    public void destroy() {

    }
}

如何在业务中获取当前的登录信息?

public class JobServiceImpl implements JobService {

    private JobDao jobDao=new JobDaoImpl();

    @Override
    public QueryResult findJobByPage(QueryInfo queryInfo) {
        
        //!!!!重点   获取当前线程的代码
       

>  Map user = UserThreadLocal.getUser();
>         System.out.println(user+"------------------");

        return jobDao.findJobByPage(queryInfo.getStartIndex(),queryInfo.getLimit());
    }
 }

6 前端登录处理
前端登录成功后把token设置到sessionStorage
// 进行登录操作

 form.on('submit(login)', function (data) {
        data = data.field;

        $.ajax({
            type: "POST",
            url: "http://www.j236.com/crm/login?method=to",
            data: data ,
            success: function(res){

                if(res.code==0){

                    //前端登录成功后把token设置到sessionStorage
                    sessionStorage.setItem("token",res.data)

                    layer.msg('登录成功', function () {
                        window.location = '../index.html';
                    });
                }else{
                    layer.msg(res.msg);
                }
            }
        });

        return false;
    });

前端在除了登录外的所有ajax请求都携带token给后端

$.ajax({
                type: "POST",
                url: "http://www.j236.com/crm/job?method=add",
                data: filed ,
                beforeSend: function (XMLHttpRequest) {
                    //前端携带的token信息
                    XMLHttpRequest.setRequestHeader("token", sessionStorage.token);
                },
                success: function(obj){

}
     });
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值