SpringBoot使用JWT实现Token登录校验

JWT全称JSON Web Token,实现过程简单的说就是用户登录成功之后,将用户的信息进行加密,然后生成一个token返回给客户端,与传统的session交互没太大区别。

区别就是token存放了用户的基本信息,更直观一点就是将原本放入redis中的用户数据,放入到token中去了。

1、导入依赖

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

2、生成token

public static String getBearerToken(String userId, Integer expireSecond) {
    Date date = new Date(System.currentTimeMillis() + expireSecond * 1000);
    //json web token构建
     return Jwts.builder()
        //此处的subject可以用一个用户名,也可以是多个信息的组合,根据需要来定
        .setSubject(userId)
        //设置token过期时间,24小時
        .setExpiration(date)
        //设置token签名、密钥
        .signWith(SignatureAlgorithm.HS512, jwtKey)
        .compact();
}

3、解析token

public static String parseBearerToken(String token) {
    token = token.replace("Bearer ", "");
     return Jwts.parser()
        //签名、密钥
        .setSigningKey(jwtKey)
        .parseClaimsJws(token)
        .getBody()
        .getSubject();
}

4、监听网络请求

@Configuration
@Slf4j
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService userService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                //关闭跨站请求防护
                .cors().and().csrf().disable()
                .authorizeRequests()
                //需要授权后访问
                .anyRequest().authenticated()
                .and()
                //增加登录拦截
                .addFilter(new JWTLoginFilter(authenticationManager()))
                //增加是否登陸过滤
                .addFilter(new JWTAuthenticationFilter(authenticationManager()))
                //前后端分离是无状态的,所以暂时不用session,將登录信息保存在token中。
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Override
    public void configure(WebSecurity web) {
        //允许不登录就可以访问的方法,多个用逗号分隔
        web.ignoring().antMatchers("/api/demo/**","/api/test/test");
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService())
                .passwordEncoder(passwordEncoder());
    }

    @Bean
    public UserDetailsService userDetailsService() {
        //校验用户
        return username -> {
            UserEntity user = userService.getUserByName(username);
            if (user == null) {
                log.error("loadUserByUsername user not found {}", username);
                return null;
            }
            return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(), emptyList());
        };
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

5、验证是否登录

@Slf4j
public class JWTAuthenticationFilter extends BasicAuthenticationFilter {
    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    /**
     * 对请求进行过滤
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
        try {
            log.info("doFilterInternal"+request.getRequestURI());
            //请求体的头中是否包含Authorization
            String header = request.getHeader("Authorization");
            //Authorization中是否包含Bearer,有一个不包含时直接返回
            if (header == null || !header.startsWith("Bearer ")) {
                responseJson(response);
                return;
            }
            //获取权限失败,会抛出异常
            UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
            //获取后,将Authentication写入SecurityContextHolder中供后序使用
            SecurityContextHolder.getContext().setAuthentication(authentication);
            chain.doFilter(request, response);
        } catch (Exception e) {
            log.info("doFilterInternal"+e.toString());
            responseJson(response);
            e.printStackTrace();
        }
    }

    /**
     * 未登录时的提示
     */
    private void responseJson(HttpServletResponse response){
        try {
            //未登录时,使用json進行提示
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            PrintWriter out = response.getWriter();
            Map<String,Object> map = new HashMap<String,Object>();
            map.put("code", HttpServletResponse.SC_FORBIDDEN);
            map.put("message","请登录!");
            out.write(new ObjectMapper().writeValueAsString(map));
            out.flush();
            out.close();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }

    /**
     * 通过token,获取用户信息
     */
    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        if (token != null) {
            //通过token解析出用户信息
            String user = JwtUtil.parseBearerToken(token);
            //不为null,返回
            if (user != null) {
                return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
            }
            return null;
        }
        return null;
    }
}

6、登录拦截

@Slf4j
public class JWTLoginFilter extends UsernamePasswordAuthenticationFilter {
    private AuthenticationManager authenticationManager;

    public JWTLoginFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    /**
     * 接收并解析用户凭证,出現错误时,返回json数据前端
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res){
        try {
            UserEntity user = new ObjectMapper().readValue(req.getInputStream(), User.class);
            return authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            user.getUserName(),
                            user.getPassword(),
                            new ArrayList<>())
            );
        } catch (Exception e) {
            try {
                //未登录提示账号密码错误
                res.setContentType("application/json;charset=utf-8");
                res.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                PrintWriter out = res.getWriter();
                Map<String,Object> map = new HashMap<String,Object>();
                map.put("code",HttpServletResponse.SC_UNAUTHORIZED);
                map.put("message","账号或密码错误!");
                out.write(new ObjectMapper().writeValueAsString(map));
                out.flush();
                out.close();
            } catch (Exception e1) {
                e1.printStackTrace();
            }
            throw new RuntimeException(e);
        }
    }

    /**
     * 用户登录成功后,生成token,并且返回json数据给前端
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain, Authentication auth){
        String userName = ((UserDetails) auth.getPrincipal()).getUsername();
        String token = JwtUtil.getBearerToken(userName, 24*3600);
        //返回token
        res.addHeader("Authorization", "Bearer " + token);

        try {
            //登录成功時,返回json格式进行提示
            res.setContentType("application/json;charset=utf-8");
            res.setStatus(HttpServletResponse.SC_OK);
            PrintWriter out = res.getWriter();
            Map<String,Object> map = new HashMap<String,Object>();
            map.put("code",HttpServletResponse.SC_OK);
            map.put("message","登陆成功!");
            map.put("token","Bearer " + token);
            out.write(new ObjectMapper().writeValueAsString(map));
            out.flush();
            out.close();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/watson2017/article/details/124806069