Spring Security从表单验证到token验证

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2016/03/02/spring-security-form-to-token/

对于任何需要认证的系统,Spring Security无疑是一个很好的选择。

无论是从认证本身,还是权限控制,Spring Security都有极好的支持。

Form登录是一种极为常见的方式,用户输入用户名和密码,post登录信息,认证之后登录信息保存在session之中。

但是随着架构演进,前后端逐渐分离,之前的大部分逻辑都变成了API供前端调用,而Form登录逐渐成为累赘,调试上的困难。这个时候就可以考虑换为token模式,进而将后端API stateless化。

Token的生成和解析

第一步是选择token的生成和解析,我们来个简单的,token中只包含加密后的用户名,具体生成才是JWT的HS512加密。

先配置一个登录成功后的响应AuthSuccessHandler

public class AuthSuccessHandler implements AuthenticationSuccessHandler {
    public static final String SECRET_KEY = "0Qx*@S7q";

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {
        response.setStatus(HttpStatus.OK.value());
        JsonNodeFactory factory = JsonNodeFactory.instance;
        ObjectNode objectNode = factory.objectNode();
        objectNode.set("status", factory.textNode("success"));
        objectNode.set("token", factory.textNode(createToken(authentication)));
        PrintWriter out = response.getWriter();
        out.write(objectNode.toString());
        out.close();
    }

    private String createToken(Authentication authentication) {
        return Jwts.builder()
                .setSubject(authentication.getName())
                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                .compact();
    }
}

配置中添加一句

and().formLogin().successHandler(new AuthSuccessHandler())

这样登录成功后会返回类似这样的json

{
    "status": "success",
    "token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ4aWFuIn0.O5xEDP5JCMcrQzpRaswsrhWfZ1Wlw7r8-94KU14G6wN_nSKH0YZZprKaoiuiNIRXWbmkX68KFx2fts1DPbPnOw"
}

Token认证

现在我们有了token,任何消费API的请求都需要在header中包含这个token,然后再根据这个token给予用户的请求完成认证,Spring Security的Pre-Auth就是合适的方案。

当我们获取token以后直接解码获得用户名,并给予当前访问认证。

final String token = request.getHeader(AUTH_HEADER_NAME);
        if (!StringUtils.isEmpty(token)) {
            String username = Jwts.parser()
                    .setSigningKey(AuthSuccessHandler.SECRET_KEY)
                    .parseClaimsJws(token)
                    .getBody()
                    .getSubject();
            if (username!= null) {
                logger.info(String.format("User login in with user name: %s", username));
                return new UsernamePasswordAuthenticationToken(username, "", Lists.<GrantedAuthority>newArrayList());
            }
        }
        return null;

这个一个Filter,它的位置位于UsernamePasswordAuthenticationFilter之前,在配置中直接配置

.addFilterBefore(new TokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

这样就完成了token的认证,只要请求包含有效的token,那么就能访问授权后的资源。

其他

这只是一个简单的例子,token的生成方式非常脆弱,也没有过期超时等等的验证。Spring Security还有oauth模块,可以使用其中的tokenStore等等去完善。

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2016/03/02/spring-security-form-to-token/

发表评论