跳至主要內容

Springboot Security oauth+jwt

OrangBus大约 3 分钟

session登录

 <parent>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-parent</artifactId>
     <version>2.6.7</version>
     <relativePath/> <!-- lookup parent from repository -->
</parent>
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Oauth2.0

流程

模式

  • 授权码模式(authorization code)
  • 简化模式(implicit)
  • 密码模式(resource owner password credentials)
  • 客户端模式(client credentials)

Oauth2授权主要由两部分组成:

  • Authorization server:认证服务
  • Resource server:资源服务

引入Security依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>SpringBoot-Study</artifactId>
        <groupId>com.orangbus</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>jwt-server</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
<!--        引入spring-cloud 版本-->
        <pring-cloud>Greenwich.SR2</pring-cloud>
    </properties>

    <dependencies>
        <!--spring cloud oauth2-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <!--spring cloud security-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>

        <!--JWT-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
    </dependencies>

    <!--spring cloud-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

1、自定义密码解析器

2、实现登录授权两个方法

授权服务器

资源服务器

1、获取授权

ip/oauth/authorize?response_type=code&client_id=admin&redirect_url=https://baidu.com&scope=all

点击授权,得到授权码, 通过授权码 拿到acces_token

登录成功或者失败的页面需要是一个post请求

授权码模式

  1. 需要提供appid和app密码

  2. 配置回调地址

  3. 验证token接口


Token

依赖

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

生成Token

package com.orangbus.jwt.util;

import com.orangbus.jwt.empty.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;

import java.security.Key;
import java.util.Date;

/**
 * jwt
 */
@Component
public class JwtUtil {

    // 加盐
    private final String SALT="orangbus";
    // token 标识符
    private final String TOKEN_NAME="user";

    /**
     * 生成令牌
     */
    public String token(User user){
        // 去除密码
        if (user.getPassword() != null){
            user.setPassword(null);
        }
        // 有效时间
        long now =System.currentTimeMillis();
        Date expTime = new Date(now + 30*30*1000);
        JwtBuilder jwtBuilder = Jwts.builder();
        String token = jwtBuilder.setId("1024")
                // 签发者
                .setIssuer("orangbus")
                // 面向用户
                .setSubject("orangbus.cn")
                // 接受jwt一方
                .setAudience("orangbus")
                // 过期时间
                .setExpiration(expTime)
                // 签发时间
                .setIssuedAt(new Date())
                // 身份标识
                .signWith(SignatureAlgorithm.HS256, SALT)
                // 用户数据
                .claim(TOKEN_NAME,user)
                .compact();
        return token;

    }

    /**
     * 检验是否过期
     */
    public Boolean checkTokenExp(String token){
        Claims claims = Jwts.parser()
                .setSigningKey(SALT)
                .parseClaimsJws(token)
                .getBody();
        long now = System.currentTimeMillis();
        // 获取失效时间
        long expirationDate = claims.getExpiration().getTime();
        if (expirationDate < now){
            return true;
        }else{
            return false;
        }
    }

    /**
     * 用户token换取用户信息
     */
    public Object getUserInfoByToken(String token){
        Claims claims = Jwts.parser()
                .setSigningKey("orangbus")
                .parseClaimsJws(token)
                .getBody();
        Object user = claims.get(TOKEN_NAME);
        return user;
    }
}

iss
issjwt签发者,谁创建的
subjwt面像的用户
aud
exp
nbf
iat
jti
image-20211017221945784
image-20211017221945784

Jwt

JWT组成的部分

1、Header(头)

记录令牌类型、签名算法等 例如:

2、Payload(有效载荷)

携带一些用户信息 例如

3、Signature(签名)

防止Token被篡改、确保安全性 例如 计算出来的签名,一个字符串

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.6.0</version>
</dependency>
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.digest.Md5Crypt;

import java.io.UnsupportedEncodingException;
import java.util.Base64;

public class JWTDemo04 {

    public static void main(String[] args) throws UnsupportedEncodingException {
        String jwtSecret="mayikt";
        // jwt jwtHeader
        JSONObject jwtHeader = new JSONObject();
        jwtHeader.put("alg","HS256");
        jwtHeader.put("typ","jwt");
        // jwt playload 
        JSONObject jwtPlayload = new JSONObject();
        jwtPlayload.put("userName","yushengjun644");
        jwtPlayload.put("age",22);
        //base64JwtHeader
        String base64JwtHeader= Base64.getEncoder().encodeToString(jwtHeader.toJSONString().getBytes());
        String base64JwtPlayload= Base64.getEncoder().encodeToString(jwtPlayload.toJSONString().getBytes());
        // 使用MD5 生成签名
        String signature = DigestUtils.md5Hex(jwtPlayload.toJSONString() + jwtSecret);
        String jwt=base64JwtHeader+"."+base64JwtPlayload+"."+signature;
        System.out.println(jwt);
        // 解密
        String jwtPlayloadStr=new String(Base64.getDecoder().decode(jwt.split("\\.")[1].getBytes()),
                "UTF-8");
        String jwtsignatureStr=jwt.split("\\.")[2];
        System.out.println(DigestUtils.md5Hex(jwtPlayloadStr+jwtSecret).equals(jwtsignatureStr));
      

    }
}

表单认证