Jwt跨域认证方案

目录

1 常见的用户认证方案

2 Session认证

2.1 早期Session认证

2.2 改进的Session认证

3 JwtToken认证

3.1 Token介绍

3.2 JwtToken

3.2.1 Header头部

3.2.2 Payload载荷

3.2.3 Signature签名

4 SpringBoot集成实现Jwt认证

4.1 实现

4.2 测试


码字不易,喜欢就点个关注❤,持续更新技术内容。相关资料请私信。

相关内容:

第一篇:原生JS到Vue前端工程化开发_js转vue代码-CSDN博客

第一篇:SpringBoot项目的创建和开发_Maxlec的博客-CSDN博客

1 常见的用户认证方案

互联网服务离不开用户认证。常见的用户认证鉴权方式如下:

  1. Cookie Session

  2. JWT,Token 认证

  3. OAuth2 认证

  4. SSO 单点登录

  5. 扫码认证

2 Session认证

2.1 早期Session认证

早期互联网以 web 为主,客户端是浏览器,所以 Cookie-Session 方式最那时候最常用的方式,直到现在,一些 web 网站依然用这种方式做认证。

Session认证一般流程是:

  1. 用户向服务器发送用户账户和密码

  2. 服务器验证通过后,在当前对话(Session)看里面保存相关数据,比如用户角色、登录时间等

  3. 服务向用户返回一个session_id,写入用户的Cookie

  4. 用户随后的每一次请求,都会通过Cookie,将session_id传回服务器

  5. 服务器收到session_id,找到前期保存的数据,由此得知用户的身份

由于传统的 Cookie-Session 认证存在诸多问题,可以把上面的方案改造一下。改动的地方如下:

  1. 不用 cookie 做客户端存储,改用其他方式,web 下使用 local storage,APP 中使用客户端数据库,这样就实现了跨域,并且避免了 CSRF ;

  2. 服务端也不存 Session 了,把 Session 信息拿出来存到 Redis 等内存数据库中,这样即提高了速度,又避免了 Session 同步问题;

2.2 改进的Session认证

经过改造之后变成了如下的认证过程:

  1. 用户输入用户名、密码或者用短信验证码方式登录系统;

  2. 服务端经过验证,将认证信息构造好的数据结构存储到 Redis 中,并将 key 值返回给客户端;

  3. 客户端拿到返回的 key,存储到 local storage 或本地数据库;

  4. 下次客户端再次请求,把 key 值附加到 header 或者 请求体中;

  5. 服务端根据获取的 key,到 Redis 中获取认证信息;

session认证的方式应用非常普遍,但也存在一些问题,扩展性不好。如果是服务器集群部署,或者是跨域的服务导向架构,就要求session数据共享,每台服务器都能够读取session,针对这种问题有两种解决方案:

  1. session数据持久化,写入数据库或别的持久层。各种服务收到请求后,都向持久层请求数据。这种方案的优点是架构清晰,缺点是工程量比较大。

  2. 一种是服务器不再保存session数据,所有数据都保存在客户端,每次请求都发回服务器。Token认真就是这种方案的一个代表。

3 JwtToken认证

3.1 Token介绍

Token是在服务端产生的一串字符串,是客户端访问资源接口(API)时所需要的资源凭证,token认证的一般流程如下:

  1. 用户在客户端提交账户和密码表单请求登录,服务端接收到表单验证账户和密码,验证成功,服务端生成一个token响应返回给客户端,客户端接收并存储在cookie中或者localstorage中。

  2. 客户端每次向服务端请求资源时都需要带上服务端签发的token,服务端接收到请求,验证请求中的token是否合法,验证成功就允许客户端访问,响应数据。

token解析的特点:

  1. 服务器不需要保存任何的session或者cookie。,基于token的用户认证是一种由服务端无状态的事件驱动的认证方式。

  2. 解析token的计算时间换取了session的存储空间,从而减轻服务器的压力,减少频繁的数据库查询。

  3. token认证完全由应用管理,所以token可以避开同源策略。

3.2 JwtToken

JSON Web Token(JWT)是一个非常轻巧的规范,是目前最流行的跨域认证解决方案。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。

Jwt的原理是就是Token认证,在服务认证以后,生成一个JSON对象,返回给客户端用户。用户与服务器通信时,都要带上这个JSON对象。服务器完全靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名。

特点:

  1. 客户端收到服务器返回的JWT字符串后可以存储在Cookie中,也可以存储在localstorage中。

  2. 客户端每次与服务器通信,都要带上这个JWT字符串,可以把它放在Cookie中自动发送,但这样不能跨域,更好的做法是放在HTTP请求的头信息"Authorization"字段里面,单独发送。

优点

  1. 使用 json 作为数据传输,有广泛的通用型,并且体积小,便于传输;

  2. 不需要在服务器端保存相关信息;

  3. jwt 载荷部分可以存储业务相关的信息(非敏感的),例如用户信息、角色等;

JWT由三个部分组成:Header、Payload、Signature,三部分最终组合为完整的字符串,中间用"."隔开:Header.Payload.Signature。

3.2.1 Header头部

Header部分是一个JSON对象,描述JWT的元数据:

{
    "alg": "HS256",
    "typ": "JWT"
}

alg属性是签名的算法,默认是HS256》typ属性表示这个令牌(token)的类型(type),JWT令牌统一写为JWT。最后将JSON使用Base64URL算法转换成字符串。

3.2.2 Payload载荷

Payload部分也是一个JSON对象,用来存放实际需要传递的数据。JWT规定了7个官方字段,如签发人、生效时间、过期时间、编号等等。这个JSON对象也使用Base64URL算法转换成字符串。

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

3.2.3 Signature签名

Signature部分是对前两部分的签名,防止数据被篡改。首先需要指定一个密钥(secret)。这个密钥只有服务器知道,不能泄露给用户。

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  abcdefabcdefabcdef
)

算出签名以后,把Header、Payload、Signature三个部分拼成一个字符串,每个部分之间使用"."分隔,返回给客户端。

4 SpringBoot集成实现Jwt认证

4.1 实现

创建SpringBoot项目,写好相关API后,集成Jwt的首先一步是引入Jwt的依赖坐标:

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

创建Jwt工具类,在类中定义生成JwtToken的方法,以及解析token的方法:

public class JwtUtils {
    //32个字符密钥
    private static final String secret = "abcdefghiabcdefghiabcdefghi";
​
    //生成token
    public static String generateToken(User user){
        //七天过期
        long expire = 604800;
        Date expiration = new Date(System.currentTimeMillis() + 1000*expire);
        
        // 设置载荷
        Map<String, Object> claims = new HashMap<>();
        claims.put("uname",user.getUname());
        claims.put("pwd", user.getPwd()); // 一般不以密码为载荷,因为token可能被解析
​
        // 返回JwtToken字符串
        return Jwts.builder()
                .signWith(SignatureAlgorithm.HS256,secret) // 签名算法
                .setClaims(claims)
                .setExpiration(expiration)
                .compact();
    }
​
    //解析token
    public static Claims getClaimsByToken(String token) {
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }
}

然后在业务层中定义处理方法,验证用户传递过来的用户信息是否正确,通过后返回包含token的结果集:

@Service
public class UserService {
​
    @Autowired
    UserMapper userMapper;
    // 传入账户和密码,生成token
    public TokenResult GetLoginToken(User user)
    {
        List<User> list = userMapper.queryUserByName(user.getUsername());
        TokenResult result = new TokenResult();
        if (list.size() > 0)
        {
            if (Objects.equals(list.get(0).getPassword(), user.getPassword()))
            {
                String token = JwtUtils.generateToken(user);
                Map<String, Object> data = new HashMap<>();
                data.put("token", token);
                result.setCode(20000);
                result.setSuccess(true);
                result.setMessage("成功");
                result.setData(data);
            }
            else
            {
                result.setCode(0);
                result.setSuccess(false);
                result.setMessage("密码错误");
            }
        }
        else
        {
            result.setCode(0);
            result.setSuccess(false);
            result.setMessage("账号错误");
        }
        return result;
    }
}

接下来就可以在控制器接口方法中直接使用,当用户输入账户和密码点击登录调用远程调用以下接口,并传递账户和密码的表单,后端就可以进行账户和密码的验证,通过后就会生成返回一个token:

@RestController
@RequestMapping("/user")
@CrossOrigin
public class UserController {
    @Autowired
    private UserService userService;
​
    @ApiOperation("接收登录表单生成token")
    @PostMapping("/login")
    //前端一般传递的数据是json格式,必须使用对象接收,同时需要添加@RequestBody注解
    public TokenResult login(@RequestBody User user){
​
        // 传入用户包含账户和密码的对象,在验证通过后返回包含token的结果集
        TokenResult tokenResult = userService.GetLoginToken(user);
​
        //返回包含token的结果集
        return tokenResult;
    }
}

4.2 测试

首先打开我已经配置好Swagger调试页面进行调试,相关配置可以看我另外一篇SpringBoot的文章。如下图成功返回包含JwtToken的结果集:

现在打开启动前端项目,相关的内容可以看Vue的文章,启动项目进入登录页面输入账户和密码:

成功响应并跳转成功:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Maxlec

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值