SpringBoot中使用 JWT + 拦截器实现登录验证

旧的方法存在缺点

之前的策略是,UUID + redis + 拦截器的思路。

服务器端在验证 roomid 和 password相匹配之后,使用 UUID 生成一个字符串作为 token ,接着往 Redis 服务中写入一个映射(token, roomid), 设置过期时间为20分钟, 并且把token 通过响应返回给客户端。因此,客户端便可以使用这个 UUID 产生的 token 来访问。

对于需要携带 token 的请求,安排了一个拦截器来检查这些请求,检验请求所携带的 token 与 roomid 是否与 Redis 中已有的映射相匹配,若匹配,说明已经授权可以可以放行,若不匹配,则拒绝请求。

缺点在于:

  • 服务器端需要使用 Redis 保存许多键值对,占用一定的内存空间。
  • 客户端获取的值是单纯的值,当用户太多时,UUID 的数目变得过多会加大被猜中的概率。

JWT

token 的三部分中,第一部分是头,第二部分是负载,第三部分是签名,一二部分都是base64加密,不能存放敏感信息。
如果客户端私自修改过期时间,token 的验证环节可以检测出来。(有使用密钥对过期时间进行加密)
如果修改客户端 roomid,是否意味着可以冒用他人的 token?token 生成过程有把负载部分考虑在内,验证的时候可以察觉到负载被修改。
使用 JWT 是用时间换空间,节省了服务器端的空间。

使用 JWT(JSON Web Token) 的方法

maven 中添加依赖,引入 Java-jwt 项目。

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

服务器有一个不能公开的密钥。

服务器端在验证 roomid 和 password 之后,Token 签名算法使用密钥根据 payload 的内容生成签名,可以配置token 的过期时间(本项目配置的是 1 小时),token 的生成相当于服务器对验证通过者的授权,授权其可进行 1 小时的免密码畅行。最终得到一个 token 通过响应返回给客户端『generate 方法』。 客户端可以使用这个 token 进行请求。

对于需要携带 token 的请求,安排了一个拦截器进行检查,『validate 方法』使用 token 校验算法来检查请求所携带的 token的签名是否有效(过期或者 roomid 与签名内容不匹配都会被认为无效)。若 token 检验正确,则放行,若检验错误,则拒绝请求。

下方是 token 的生成与验证,其中 secret 是自己设定的密钥(是一个字符串,我的密钥可不能公开贴出来)。

token 生成过程:

 public static String generate(String roomid){
        String token = "";
        try{
            Algorithm algorithm = Algorithm.HMAC256(secret);
            Map<String,Object> map = new HashMap<>();
            map.put("roomid",roomid);
            token = JWT.create().withIssuer("auth0")
                    .withPayload(map)
                    .withExpiresAt(new Date(System.currentTimeMillis() + (long)3600*1000))
                    .sign(algorithm);
        }catch(JWTCreationException e){
            e.printStackTrace();
        }
        return token;
    }

token 的验证,验证通过则返回 roomid,验证不通过则返回 null。

public static String validate(String roomid, String token){
        DecodedJWT jwt = null;
        try{
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier jwtVerifier = JWT.require(algorithm)
                    .withClaim("roomid",roomid)
                    .withIssuer("auth0").build();
            jwt = jwtVerifier.verify(token);
            if (jwt == null )return null;
            Claim claim = jwt.getClaim("roomid");
            if (claim == null )return null;
            return claim.asString();
        }catch (JWTVerificationException e){
            return null;
        }

    }

参考:https://github.com/auth0/java-jwt

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个使用 Spring Boot、JWT拦截器实现登录验证的示例代码: 1. 添加 JWT 依赖 在 pom.xml 文件添加以下依赖: ```xml <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.2</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.2</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.2</version> <scope>runtime</scope> </dependency> ``` 2. 创建 JWT 工具类 ```java import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; import org.springframework.stereotype.Component; import java.security.Key; import java.util.Date; import java.util.HashMap; import java.util.Map; @Component public class JwtUtil { private final Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256); public String generateToken(String subject) { return Jwts.builder() .setClaims(new HashMap<>()) .setSubject(subject) .setExpiration(new Date(System.currentTimeMillis() + 60 * 60 * 1000)) .signWith(key) .compact(); } public boolean validateToken(String token) { try { Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); return true; } catch (Exception e) { return false; } } public String getUsernameFromToken(String token) { Claims claims = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody(); return claims.getSubject(); } } ``` 3. 创建拦截器 ```java import com.example.demo.jwt.JwtUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.lang.reflect.Method; @Component public class AuthenticationInterceptor implements HandlerInterceptor { @Autowired private JwtUtil jwtUtil; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization"); if (token != null && jwtUtil.validateToken(token)) { String username = jwtUtil.getUsernameFromToken(token); request.setAttribute("username", username); return true; } else { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return false; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); LoginRequired loginRequired = method.getAnnotation(LoginRequired.class); if (loginRequired != null && modelAndView != null) { modelAndView.addObject("username", request.getAttribute("username")); } } } ``` 4. 创建注解 ```java import java.lang.annotation.*; @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface LoginRequired { } ``` 5. 创建控制器 ```java import com.example.demo.interceptor.LoginRequired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/") public String index() { return "Hello World"; } @GetMapping("/hello") @LoginRequired public String hello() { return "Hello " + SecurityContextHolder.getContext().getAuthentication().getName(); } } ``` 6. 配置拦截器 ```java import com.example.demo.interceptor.AuthenticationInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Autowired private AuthenticationInterceptor authenticationInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authenticationInterceptor).addPathPatterns("/**"); } } ``` 7. 创建登录控制器 ```java import com.example.demo.jwt.JwtUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; @RestController public class LoginController { @Autowired private JwtUtil jwtUtil; @PostMapping("/login") public Map<String, Object> login(@RequestBody Map<String, String> params) { String username = params.get("username"); String password = params.get("password"); // TODO: 验证用户名和密码 String token = jwtUtil.generateToken(username); Map<String, Object> result = new HashMap<>(); result.put("token", token); return result; } } ``` 在这个示例,我们创建了一个 JWT 工具类来生成和验证 JWT,创建了一个拦截器验证用户是否登录,并使用 @LoginRequired 注解来标记需要登录验证的方法。我们还创建了一个登录控制器来生成 JWT。通过这个示例,您可以了解如何使用 Spring Boot、JWT拦截器实现登录验证

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值