Spring Security JWT

首先需要创建2个过滤器. JwtLoginFilter 和 JwtAuthenticationFilter .

JwtLoginFilter 用来处理用户登录请求.

JwtAuthenticationFilter 用来处理JwtToken的验证解析.

/**
 * @author: 阮胜
 * @date: 2018/7/10 8:42
 */
public class JwtLoginFilter extends AbstractAuthenticationProcessingFilter {

    private static final String POST = "POST";
    private AuthenticationSuccessHandler successHandler = new JwtLoginSucessHandler();
    private AuthenticationFailureHandler failureHandler = new JwtLoginFailureHandler();

    public JwtLoginFilter(AuthenticationManager authenticationManager) {
        super(new AntPathRequestMatcher("/user/login", "POST"));
        setAuthenticationManager(authenticationManager);
    }


    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException, IOException, ServletException {
        if (!request.getMethod().equals(POST)) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + request.getMethod());
        }

        String username = request.getParameter("username");
        String password = request.getParameter("password");

        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {

            PrintWriter writer = response.getWriter();
            writer.write("用户名或者密码为空");
            writer.close();
            return null;
        }
        username = username.trim();
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
                username, password);
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
        return this.getAuthenticationManager().authenticate(authRequest);
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        JwtTokenUtil jwtTokenUtil = new JwtTokenUtil();
        JwtToken jwtToken = new JwtToken(authResult.getName(), authResult.getAuthorities().iterator().next().toString(), jwtTokenUtil.generateExpirationDate());
        String jwtTokenStr = jwtTokenUtil.generateToken(jwtToken);
        response.addHeader("Authorization", jwtTokenStr);
        successHandler.onAuthenticationSuccess(request, response, authResult);
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        failureHandler.onAuthenticationFailure(request, response, failed);
    }

    public void setSuccessHandler(AuthenticationSuccessHandler successHandler) {
        this.successHandler = successHandler;
    }

    public void setFailureHandler(AuthenticationFailureHandler failureHandler) {
        this.failureHandler = failureHandler;
    }
}

/**
 * @author: 阮胜
 * @date: 2018/7/10 10:44
 */
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {
    public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String jwtTokenStr = request.getHeader("Authorization");
        if (!StringUtils.isEmpty(jwtTokenStr)) {
            try {
                if (!jwtTokenUtil.validateToken(jwtTokenStr)) {
                    throw new InvalidJwtTokenException();
                }
                JwtToken jwtToken = jwtTokenUtil.parseJwtToken(jwtTokenStr);
                UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(jwtToken.getUsername(), null
                        , AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_".concat(jwtToken.getRole())));
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            } catch (Exception e) {
                sendError(response, "无效的Token");
                return;
            }
        }
        chain.doFilter(request, response);
    }

    private void sendError(HttpServletResponse response, String msg) throws IOException {
        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
        response.setContentType("text/plain;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.write(msg);
        writer.close();
    }
}

配置类:

/**
 * @author: 阮胜
 * @date: 2018/7/10 8:33
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private final AccessDeniedHandler accessDeniedHandler;
    private final AuthenticationEntryPoint authenticationEntryPoint;
    private final UserDetailServiceImpl userDetailsService;

    public SecurityConfig(AccessDeniedHandler accessDeniedHandler, AuthenticationEntryPoint authenticationEntryPoint, UserDetailServiceImpl userDetailsService) {
        this.accessDeniedHandler = accessDeniedHandler;
        this.authenticationEntryPoint = authenticationEntryPoint;
        this.userDetailsService = userDetailsService;
    }

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

    @Bean
    public JwtLoginFilter jwtLoginFilter() throws Exception {
        JwtLoginFilter jwtLoginFilter = new JwtLoginFilter(authenticationManager());
        jwtLoginFilter.setAuthenticationSuccessHandler((request, response, authentication) -> {
            System.out.println("success");
        });
        jwtLoginFilter.setAuthenticationFailureHandler((request, response, exception) -> {
            System.out.println("false");
        });
        return jwtLoginFilter;
    }

    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {
        return new JwtAuthenticationFilter(authenticationManager());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/admin", "/admin/info").hasRole("ADMIN")
                .anyRequest().permitAll()
                .and().userDetailsService(userDetailsService)
                //如果已经登录,但没有访问资源的权限,则调用该Handler
                .exceptionHandling().accessDeniedHandler(accessDeniedHandler)
                //如果未登录,没有权限则调用该EntryPoint
                .authenticationEntryPoint(authenticationEntryPoint)
                // 无状态的Session机制(即Spring不使用HTTPSession),对于所有的请求都做权限校验
                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                //关闭跨域保护
                .and().csrf().disable();

        //把自己写的2个filter加入到过滤器链中
        http.addFilterBefore(jwtLoginFilter(), UsernamePasswordAuthenticationFilter.class)
                .addFilter(jwtAuthenticationFilter());
    }
}

工具类:

package com.example.springsecurityjwtdemo.util;

import com.example.springsecurityjwtdemo.exception.InvalidJwtTokenException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 阮胜
 * @date 2018/7/5 21:21
 */
@Component
public class JwtTokenUtil implements Serializable {

    private static final long serialVersionUID = -3301605591108950415L;

    public static final String USERNAME = "username";
    public static final String ROLE = "role";
    public static final String CREATED_DATE = "createdDate";
    private static final String SECRET = "jwt_secret";
    private static final int EXPIRED_TIME_SECONDS = 60 * 60 * 24 * 7;

    public JwtToken parseJwtToken(String token) throws InvalidJwtTokenException {
        Claims claims = obtainClaims(token);
        if (claims == null) {
            throw new InvalidJwtTokenException();
        }
        return new JwtToken(claims.get(USERNAME).toString(), claims.get(ROLE).toString(), claims.get(CREATED_DATE, Date.class));
    }

    public String obtainUsername(String token) {
        String username;
        try {
            final Claims claims = obtainClaims(token);
            username = claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }


    public Date obtainExpiredDate(String token) {
        Date expiration;
        try {
            final Claims claims = obtainClaims(token);
            expiration = claims.getExpiration();
        } catch (Exception e) {
            expiration = null;
        }
        return expiration;
    }

    private Claims obtainClaims(String token) {
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(SECRET)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }


    public Date generateExpirationDate() {
        long expired = System.currentTimeMillis() + EXPIRED_TIME_SECONDS * 1000;
        return new Date(expired);
    }

    private boolean isTokenExpired(String token) {
        final Date expiration = obtainExpiredDate(token);
        return expiration.after(new Date());
    }

    public String generateToken(UserDetails userDetails) {
        return generateToken(
                new JwtToken(userDetails.getUsername()
                        , userDetails.getAuthorities().iterator().next().toString()
                        , new Date()));
    }

    private String generateToken(Map<String, Object> claims) {
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate())
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .compact();
    }

    public String generateToken(JwtToken jwtToken) {
        HashMap<String, Object> tokenMap = new HashMap<>(3);
        tokenMap.put(JwtTokenUtil.USERNAME, jwtToken.getUsername());
        tokenMap.put(JwtTokenUtil.CREATED_DATE, jwtToken.getExpiredDate());
        tokenMap.put(JwtTokenUtil.ROLE, jwtToken.getRole());
        return generateToken(tokenMap);
    }

    public boolean validateToken(String token) {
        Date expiredDate = obtainExpiredDate(token);
        return expiredDate != null && expiredDate.after(new Date());
    }
}
package com.example.springsecurityjwtdemo.util;

import lombok.Data;

import java.util.Date;

/**
 * @author 阮胜
 * @date 2018/7/5 20:54
 */
@Data
public class JwtToken {
    private String username;
    private String role;
    private Date expiredDate;

    public JwtToken() {
    }

    public JwtToken(String username, String role, Date expiredDate) {

        this.username = username;
        this.role = role;
        this.expiredDate = expiredDate;
    }
}
原文地址:https://www.cnblogs.com/cearnach/p/9288971.html