前后端分离之Springboot后端

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jimo_lonely/article/details/78782262

这是上一篇博客前后端分离之Java后端的重写.
源码
前后端分离的后端主要解决的就2个问题 : 跨域访问(CORS)token校验,下面快速说明.

1.项目环境

使用Intellij IDE.
项目结构:
2

2.跨域访问

解决跨域很简单,翻一下官方文档很容易解决,我们就使用全局的通过注解实现的方式:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        //允许全部请求跨域
        registry.addMapping("/**");
    }
}

3.Token验证

这节分为2个部分,一是原理,二是代码实现.

3.1 原理

在第一篇文章里,我是这样说的:

在用户第一次登录成功后,服务端返回一个token回来,这个token是根据userId进行加密的,密钥只有服务器知道,然后浏览器每次请求都把这个token放在Header里请求,这样服务器只需进行简单的解密就知道是哪个用户了。

3.2 代码实现

避免重复造轮子,我们依然使用JWT,这个标准在2015年提出,查看RFC文档,它的一个实现JJWT

        <!-- JJWT -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>

我们要做的很简单 :登录时生成Token,拦截每次请求检查token.

3.2.1 生成Token与验证

详情查看代码注释

public class JwtUtil {
    final static String base64EncodedSecretKey = "base64EncodedSecretKey";//私钥
    final static long TOKEN_EXP = 1000 * 60;//过期时间,测试使用60秒

    public static String getToken(String userName) {
        return Jwts.builder()
                .setSubject(userName)
                .claim("roles", "user")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + TOKEN_EXP)) /*过期时间*/
                .signWith(SignatureAlgorithm.HS256, base64EncodedSecretKey)
                .compact();
    }

    /**
     * @Date:17-12-12 下午6:21
     * @Author:root
     * @Desc:检查token,只要不正确就会抛出异常
     **/
    public static void checkToken(String token) throws ServletException {
        try {
            final Claims claims = Jwts.parser().setSigningKey(base64EncodedSecretKey).parseClaimsJws(token).getBody();
        } catch (ExpiredJwtException e1) {
            throw new ServletException("token expired");
        } catch (Exception e) {
            throw new ServletException("other token exception");
        }
    }
}

3.2.2 拦截token

在spring里很好实现全局拦截,过滤器,拦截器,AOP都可以实现.
因为filter是对资源过滤,我们这里没有资源了,只有URL,而AOP着重处理过程.综合考虑,这里选择拦截器比较合适.
我们的拦截器:先检查header,取出token,验证.

public class JwtInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String authHeader = request.getHeader("Authorization");
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            throw new ServletException("invalid Authorization header");
        }
        //取得token
        String token = authHeader.substring(7);
        try {
            JwtUtil.checkToken(token);
            return true;
        } catch (Exception e) {
            throw new ServletException(e.getMessage());
        }
    }
}

注册拦截器:将登录排除

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        //允许全部请求跨域
        registry.addMapping("/**");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //添加拦截器
        registry.addInterceptor(new JwtInterceptor()).excludePathPatterns("/user/login");
    }
}

全局异常处理:

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public String handleException(Exception e) {
        return "err:" + e.getMessage();
    }
}

登录:

    @PostMapping("/login")
    public String login(User user) throws ServletException {
        String name = user.getUsername();
        String pass = user.getPassword();
        if (!"admin".equals(name)) {
            throw new ServletException("no such user");
        }
        if (!"1234".equals(pass)) {
            throw new ServletException("wrong password");
        }
        return JwtUtil.getToken(name);
    }

其他根据需要可以查看源码.

当然,整个系统我没有使用RESTful的统一API,可以自定义一个类去处理,这里不重要.

4.如何请求

将得到的token封装在header里,如下:
1

这种请求放在Axios这样的请求框架很好实现,特别是在React或Vue里.

猜你喜欢

转载自blog.csdn.net/jimo_lonely/article/details/78782262