springframework引入不进来_啥?你不知道JWT

当前在开发的系统,我是半路加入进来帮助开发几个接口,也没有特意去全面的了解这个系统的架构安全验证等问题, 最多也就是在开发功能接口时看到有不规范,设计不合理的一些对象、方法会和团队其他成员交流一下。在之前的几篇文章有介绍《简单聊一聊代码的设计原则》、《你的代码注意规范吗》。 最近开发的这个接口我需要获取一下登录者的信息,然后就被惊掉下巴了。 are you ok? 这个系统竟然没有任何验证,登录的接口只是拿着账号密码去数据库匹配了一下。 登录之后没有任何处理,没有登录记录,没有生成token等一系列操作。 后面的所有请求完全没有任何验证,也就是说 只要你能发出请求就能进入系统。跟这个项目的开发driver碰了一下 ,说是没有考虑那些东西,太麻烦。 d3005937a6f4535db6b219c98020a105.png ?那能说啥?做个系统企业级系统,也不设计一下,照着产品原型就是有一顿敲,当学生作业了吗?当然这也不能全怪一线开发人员,毕竟每个人的经验不同,主要责任我觉得还是部门领导的。这个领导已经令人失望不是一次两次了《你的领导是傻X吗》。 话说回来,开发人员考虑也太不周到了。像登录验证把JWT这套东西直接拿来用就行呗,有啥麻烦的? 其实这事我完全可以不闻不问,我只是临时加入进来帮助开发几个接口就完成任务了。 本着对得起良心,对得起公司发的工资的责任,开始吧,毕竟也不是啥难事。那么今天我们就来看看这个JWT到底麻烦不麻烦!JWT是干嘛的咱就不介绍了,直接摞代码。 首先是token的工具类
import com.hnk.lib.response.exception.ApiException;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.ObjectMapper;import io.jsonwebtoken.Claims;import io.jsonwebtoken.Jwts;import io.jsonwebtoken.SignatureAlgorithm;import io.jsonwebtoken.io.Decoders;import io.jsonwebtoken.security.Keys;import lombok.Data;import lombok.extern.slf4j.Slf4j;import javax.crypto.SecretKey;import java.util.Calendar;import java.util.Date;import java.util.HashMap;import java.util.Map;public class DefaultJwtToken {    private static String secret = "111111222222222223333333333344444444455555555fs+fsdfdsgd";    public static final String HEADER_TOKEN = "token";    private static final Map<String, String> TOKEN_MAP = new HashMap<>();    /**     * 生成token     */    public static String createToken(String subject) {        SecretKey secretKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secret));        Date nowDate = new Date();        Calendar calendar = Calendar.getInstance();        calendar.setTime(nowDate);        calendar.add(Calendar.DAY_OF_MONTH, 10);        Date expireDate = calendar.getTime();        String userToken = Jwts.builder().setHeaderParam("typ", "JWT")                .setSubject(subject).setIssuedAt(nowDate).setExpiration(expireDate).signWith(secretKey, SignatureAlgorithm.HS256).compact();        TOKEN_MAP.put(subject, userToken);        return userToken;    }    /**     * 为方便生成token     */    public static String createToken(LoginUser user) {        String subject = user.toTokenJson();        return createToken(subject);    }    public static String createRefreshToken(String subject) {        SecretKey secretKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secret));        return Jwts.builder().setHeaderParam("typ", "JWT")                .setSubject(subject).setIssuedAt(new Date())                .signWith(secretKey, SignatureAlgorithm.HS256).compact();    }    /**     * 获取token中注册信息     */    public static Claims getTokenClaim(String token) {        return Jwts.parserBuilder().setSigningKey(secret).build().parseClaimsJws(token).getBody();    }    /**     * 验证token是否过期失效     */    public static boolean isTokenExpired(Date expirationTime) {        return expirationTime.before(new Date());    }    /**     * 获取token失效时间     */    public Date getExpirationDateFromToken(String token) {        return getTokenClaim(token).getExpiration();    }    /**     * 获取用户名从token中     */    public static String getUsernameFromToken(String token) {        return getTokenClaim(token).getSubject();    }    public static LoginUser getLoginUserFromToken(String token) {        ObjectMapper objectMapper = new ObjectMapper();        try {            return objectMapper.readValue(getUsernameFromToken(token), LoginUser.class);        } catch (JsonProcessingException e) {            return null;        }    }    /**     * 获取jwt发布时间     */    public Date getIssuedAtDateFromToken(String token) throws ApiException {        return getTokenClaim(token).getIssuedAt();    }    public static Map<String, String> getTOKEN_MAP() {        return TOKEN_MAP;    }}
public class LoginUser {    private String accountName;    private String userUid;   //构造函数 set  get 省略}
添加拦截器
import com.hnk.lib.response.ApiResponse;import com.hnk.lib.response.constants.ApiCodeConstants;import io.jsonwebtoken.Claims;import org.apache.commons.lang3.StringUtils;import org.springframework.http.MediaType;import org.springframework.stereotype.Component;import org.springframework.web.method.HandlerMethod;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.BufferedWriter;import java.io.IOException;import java.io.OutputStreamWriter;import java.lang.reflect.Method;@Componentpublic class TokenInterceptor extends HandlerInterceptorAdapter {    private static final int UNAUTHORIZED_ERROR_CODE = HttpServletResponse.SC_UNAUTHORIZED;    private static final String UNAUTHORIZED_ERROR_MESSAGE = "401 unauthorized";    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {        HandlerMethod handlerMethod = (HandlerMethod) handler;        Method method = handlerMethod.getMethod();        if (method.isAnnotationPresent(Authentication.class) || handlerMethod.getBeanType().isAnnotationPresent(Authentication.class)) {            String token = request.getHeader(DefaultJwtToken.HEADER_TOKEN);            if (StringUtils.isNotBlank(token)) {                Claims claims = DefaultJwtToken.getTokenClaim(token);                if (claims != null) {                    String userName = claims.getSubject();                    String compareToken = DefaultJwtToken.getTOKEN_MAP().get(userName);                    if (token.equals(compareToken)) {                        Authentication authentication = method.getAnnotation(Authentication.class);                        if (authentication.required()) {                            if (!DefaultJwtToken.isTokenExpired(claims.getExpiration())) {                                return true;                            }                        } else {                            return true;                        }                    }                }            }            response.setStatus(UNAUTHORIZED_ERROR_CODE);            response.setContentType(MediaType.APPLICATION_JSON_VALUE);            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(response.getOutputStream()));            writer.write(new ApiResponse<>(ApiCodeConstants.TOKEN_INVALID.getCode(), ApiCodeConstants.TOKEN_INVALID.getMessage(), UNAUTHORIZED_ERROR_MESSAGE).toJson());            writer.close();            return false;        }        return true;    }}

在需要验证token的对象或方法上添加注解

@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface Authentication {    boolean required() default true;}

为了使拦截器起作用当然还要配置一下

import com.hnk.lib.token.CurrentUserMethodArgumentResolver;import com.hnk.lib.token.TokenInterceptor;import org.springframework.context.annotation.Configuration;import org.springframework.web.method.support.HandlerMethodArgumentResolver;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import javax.annotation.Resource;import java.util.List;@Configurationpublic class WebConfigFilter implements WebMvcConfigurer {    @Resource    private TokenInterceptor tokenInterceptor;    @Override    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(tokenInterceptor).addPathPatterns("/**");     }}

Token这步算是完事了。但还有一个常规的需求,就是根据Token获取当前登录者信息。具体使用方式如下:

    @GetMapping("platform-corp/list")    @ResponseBody        public Object getPlatformCorpList(@CurrentInstUser LoginUser user,@RequestParam(value = "keywords", defaultValue = "", required = false) String keywords

所以我们再加一步

@Target(ElementType.PARAMETER)@Retention(RetentionPolicy.RUNTIME)public @interface CurrentUser {}import org.apache.commons.lang3.StringUtils;import org.springframework.core.MethodParameter;import org.springframework.stereotype.Component;import org.springframework.web.bind.support.WebDataBinderFactory;import org.springframework.web.context.request.NativeWebRequest;import org.springframework.web.method.support.HandlerMethodArgumentResolver;import org.springframework.web.method.support.ModelAndViewContainer;import javax.servlet.http.HttpServletRequest;@Componentpublic class CurrentUserMethodArgumentResolver implements HandlerMethodArgumentResolver {    @Override    public boolean supportsParameter(MethodParameter parameter) {        // 如果参数类型是 User 并且有 CurrentUser 注解则支持        if (parameter.getParameterType().isAssignableFrom(LoginUser.class) &&                parameter.hasParameterAnnotation(CurrentUser.class)) {            return true;        }        return false;    }    @Override    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {        return getUser(webRequest.getNativeRequest(HttpServletRequest.class));    }    public static LoginUser getUser(HttpServletRequest webRequest) {        //取出session信息        String token = webRequest.getHeader(JwtConfig.HEADER_TOKEN);        if (StringUtils.isBlank(token)) {            return new LoginUser();        }        return JwtConfig.getLoginUserFromToken(token);    }}

登录后验证token并将token返回给前端,在后续调用接口中必须携带token进行请求。完事!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值