JWT登录认证

导入依赖

  <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
   </dependency>
/*jwt工具类*/
public class JWTUtils {
    //密钥
    public static String secret ="xyg4444";
    //过期时长
    public static long expr = 3600*24*1000;

    //1.生成token
public static String sign(User user){
    //1.指定签名的时候使用的签名算法
    SignatureAlgorithm hs256 = SignatureAlgorithm.HS256;
    //2.生成签发时间
    long nowMillis = System.currentTimeMillis();
    Date date = new Date(nowMillis);
    //3.创建playLoad的私有声明
    Map<String,Object> claims = new HashMap<>();
    claims.put("id",user.getId());
    claims.put("userName",user.getUserName());
    //4.生成签发人
    String subject = user.getUserName();


    JwtBuilder builder = Jwts.builder()
            .setClaims(claims)
            .setId(UUID.randomUUID().toString())
            .setIssuedAt(date)
            .setSubject(subject)
            .signWith(hs256,secret);
    //设置过期时间
    Date exprDate = new Date(nowMillis + expr);
    builder.setExpiration(exprDate);

    return  builder.compact();
}
    //2'验证token

    public static boolean verify(String token){
    try {
        if (StringUtil.isEmpty(token)) {
            return false;
        }
        Jwts.parser().setSigningKey(secret).parseClaimsJwt(token).getBody();
        return true;
    }catch (Exception e){
        e.printStackTrace();
        return false;
    }
}



    //3.获取用户信息
    public  static User getUser(String token) {
        try {
            if (StringUtil.isEmpty(token)) {
                throw new MyException("token不能为空");
            }
            if (verify(token)) {
                Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJwt(token).getBody();
                User user = new User();
                user.setId(Integer.parseInt(claims.get("id") + ""));
                user.setUserName(claims.get("userName") + "");
                return user;

            } else {
                throw new MyException("超时或不合法token");
            }
        } catch (Exception e) {
            throw new MyException("超时或不合法token");

        }
    }


//测试
    public static void main(String[] args) {
        User user = new User();
        user.setId(2);
        user.setUserName("admin");
        System.out.println(sign(user));
    }
}

实现HandlerInterceptor 接口 
preHandle  业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理;

通过WebMvcConfigurer 进行配置使用
/*token拦截器*/
public class TokenInterceptor  implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("token");
        User user = JWTUtils.getUser(token);
        if(user == null){
            throw  new MyException("超时或则不合法token");
        }
        //token续期
        String newToken = JWTUtils.sign(user);
        response.setHeader("token",newToken);
        request.setAttribute("user",user);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

WebMvcConfigurer配置类其实是Spring内部的一种配置方式,采用JavaBean的形式来代替传统的xml配置文件形式进行针对框架个性化定制,可以自定义一些Handler,Interceptor,ViewResolver,MessageConverter。基于java-based方式的spring mvc配置,需要创建一个配置类并实现WebMvcConfigurer 接口;

@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {

    @Bean
    public TokenInterceptor tokenInterceptor(){
        return new TokenInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
       registry.addInterceptor(tokenInterceptor()).addPathPatterns("/**").excludePathPatterns("/login");
    }
}
ddInterceptors:拦截器

    addInterceptor:需要一个实现HandlerInterceptor接口的拦截器实例
    addPathPatterns:用于设置拦截器的过滤路径规则;addPathPatterns("/**")对所有请求都拦截
    excludePathPatterns:用于设置不需要拦截的过滤规则
    拦截器主要用途:进行用户登录状态的拦截,日志的拦截等。

解决 Signed Claims JWSs are not supported. 异常
原因
这个异常是由于使用了签名的 JWT(JWS),而 io.jsonwebtoken 库不支持这种方式导致的。当使用 parseClaimsJwt 方法解析带有签名的 JWT 时,它将忽略签名并且返回包含荷载(payload)的 Claims 对象。这会导致验证 JWT 的签名失败,并抛出异常。
解决方法
使用 parseClaimsJws 方法代替 parseClaimsJwt 方法,即可解决

                Claims claims = Jwts.parser()
                .setSigningKey(secret)
                // 将 parseClaimsJwt 替换为 parseClaimsJws
                .parseClaimsJws(token)
                .getBody();

parseClaimsJws 与 parseClaimsJwt 的异同
相同
parseClaimsJwt 和 parseClaimsJws 两个方法的作用是一样的,都是解析 JWT 载荷并返回一个 Claims 对象。
不同
parseClaimsJwt 方法适用于未签名的 JWT。
parseClaimsJws 方法适用于带有 JWS 签名的 JWT。
应用场景:据所使用的 JWT 类型选择正确的方法来解析它
如果您使用的是带有 JWS 签名的 JWT,则必须使用 parseClaimsJws 方法才能正确解析 JWT 并验证签名。
如果使用的是未签名的 JWT,则可以使用 parseClaimsJwt 方法;

### 回答1: 我可以给你一些提示来帮助你实现fastapi的jwt登录认证。首先,你需要安装fastapi和pyjwt库。然后,构建一个JWT认证函数,并将它添加到登录路由上。接下来,创建一个签名密钥,并将其添加到认证函数中。最后,将签名密钥添加到环境变量中,以便可以在登录路由中使用。 ### 回答2: FastAPI是一个基于Python的现代,高性能的Web框架,它提供了快速构建API和Web应用程序的能力。JWT(JSON Web Token)是一种用于在网络应用间传递声明的安全的、基于JSON的令牌。 要实现FastAPI的JWT登录认证,需要使用以下步骤: 1. 导入所需的库: ```python from fastapi import FastAPI from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from passlib.context import CryptContext from jose import JWTError, jwt from datetime import datetime, timedelta ``` 2. 配置密码哈希和jwt密钥: ```python SECRET_KEY = "your_secret_key" ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = 30 pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/login") ``` 3. 创建用户模型和密码校验函数: ```python class User(BaseModel): username: str password: str def verify_password(plain_password, hashed_password): return pwd_context.verify(plain_password, hashed_password) ``` 4. 创建用户认证函数和生成JWT的函数: ```python async def authenticate_user(username: str, password: str): user = get_user_from_db(username) if not user: return False if not verify_password(password, user.password): return False return user def create_access_token(data: dict, expires_delta: timedelta): to_encode = data.copy() expire = datetime.utcnow() + expires_delta to_encode.update({"exp": expire}) encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) return encoded_jwt ``` 5. 创建登录路由和保护需要认证的路由: ```python app = FastAPI() @app.post("/login") async def login(form_data: OAuth2PasswordRequestForm = Depends()): user = await authenticate_user(form_data.username, form_data.password) if not user: return {"error": "Invalid username or password"} access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) access_token = create_access_token( data={"sub": user.username}, expires_delta=access_token_expires ) return {"access_token": access_token, "token_type": "bearer"} @app.get("/protected") async def protected_route(token: str = Depends(oauth2_scheme)): try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) username: str = payload.get("sub") if username is None: raise credentials_exception except JWTError: raise credentials_exception user = get_user_from_db(username) if user is None: raise credentials_exception return {"user": user} ``` 以上代码示例了一个快速实现的FastAPI JWT登录认证。在登录路由中,用户提供用户名和密码,然后校验用户名和密码是否正确,如果正确则生成一个JWT,并返回给用户。在保护的路由中,用户需要提供JWT作为认证凭证,服务器会验证JWT的有效性,并根据JWT中的信息返回相应的内容。 ### 回答3: FastAPI是一个Python的Web框架,它提供了快速构建API的能力。JWT(JSON Web Token)是一种用于身份验证和授权的开放标准。下面是一个使用FastAPI实现JWT登录认证的示例。 首先,需要安装FastAPI和PyJWT等必要的库。可以使用pip命令进行安装。 ```shell pip install fastapi pip install python-jose[cryptography] ``` 接下来,创建一个Python文件,例如`main.py`,并使用以下代码编写JWT登录认证的示例。 ```python from fastapi import FastAPI, Depends, HTTPException from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jose import jwt, JWTError from datetime import datetime, timedelta from passlib.context import CryptContext app = FastAPI() SECRET_KEY = "your-secret-key" ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = 30 fake_users_db = { 'username': { 'username': 'username', 'password': '$2b$12$Jl7haqJbg.fBx5AZvK7Hj.57A6FYRXTFmL/NyU.JvMhLDwwBUUz/e' # hashed_password: password } } pwd_context = CryptContext(schemes=['bcrypt'], deprecated='auto') oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") def verify_password(plain_password, hashed_password): return pwd_context.verify(plain_password, hashed_password) def get_password_hash(password): return pwd_context.hash(password) def get_user(username: str): if username in fake_users_db: user_dict = fake_users_db[username] return user_dict def authenticate_user(username: str, password: str): user = get_user(username) if not user: return False if not verify_password(password, user['password']): return False return user def create_access_token(data: dict, expires_delta: timedelta): to_encode = data.copy() expire = datetime.utcnow() + expires_delta to_encode.update({'exp': expire}) encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) return encoded_jwt @app.post("/token") async def login(form_data: OAuth2PasswordRequestForm = Depends()): user = authenticate_user(form_data.username, form_data.password) if not user: raise HTTPException(status_code=401, detail="Incorrect username or password") access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) access_token = create_access_token(data={"sub": user["username"]}, expires_delta=access_token_expires) return {"access_token": access_token, "token_type": "bearer"} @app.get("/me") async def read_users_me(token: str = Depends(oauth2_scheme)): try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) username: str = payload.get("sub") if username is None: raise HTTPException(status_code=401, detail="Invalid authentication credentials") except JWTError: raise HTTPException(status_code=401, detail="Invalid authentication credentials") user = get_user(username=username) if user is None: raise HTTPException(status_code=404, detail="User not found") return user ``` 上面的代码中,首先定义了一个用于存储用户信息的`fake_users_db`字典。然后使用`CryptContext`来进行密码的哈希操作。`verify_password`用于验证密码是否匹配,`get_password_hash`用于生成密码的哈希值。`get_user`用于返回指定用户名的用户信息。`authenticate_user`用于验证用户名和密码,并返回用户信息。`create_access_token`用于生成JWT令牌。 接下来,使用`@app.post`装饰器定义了一个`/token`的登录路由,接收用户名和密码,验证后生成并返回JWT令牌。 最后,使用`@app.get`装饰器定义了一个`/me`的路由,该路由需要进行JWT登录认证。在函数中解码JWT令牌,获取到用户信息并返回。 通过上述代码示例,我们实现了一个使用FastAPI实现JWT登录认证的API。可以使用`uvicorn`命令运行该API。 ```shell uvicorn main:app ``` 接下来,可以通过向`http://localhost:8000/token`发起POST请求进行登录认证,获取到JWT令牌。然后使用该令牌向`http://localhost:8000/me`发起GET请求获取当前用户信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值