美文网首页springjava
Spring Security 整合 JSON Web Toke

Spring Security 整合 JSON Web Toke

作者: 谁在烽烟彼岸 | 来源:发表于2017-07-13 15:36 被阅读1938次

    注:参考Spring Security 整合 JSON Web Token(JWT) 提升 REST 安全性,写的特别全面,本文只是学习总结

    JWT:

    基于token的鉴权机制

    基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。

    流程上是这样的:

    1.用户使用用户名密码来请求服务器

    2.服务器进行验证用户的信息

    3.服务器通过验证发送给用户一个token

    4.客户端存储token,并在每次请求时附送上这个token值

    5.服务端验证token值,并返回数据

    这个token必须要在每次请求时传递给服务端,它应该保存在请求头里, 另外,服务端要支持CORS(跨来源资源共享)策略,一般我们在服务端这么做就可以了Access-Control-Allow-Origin: *。

    JWT的构成

    第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).

    header

    jwt的头部承载两部分信息:

    声明类型,这里是jwt

    声明加密的算法 通常直接使用 HMAC SHA256

    完整的头部就像下面这样的JSON:

    {

    'typ':'JWT',

    'alg':'HS256'

    }

    然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分.

    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

    playload

    载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分

    1.标准中注册的声明

    2.公共的声明

    3.私有的声明

    标准中注册的声明(建议但不强制使用) :

    iss: jwt签发者

    sub: jwt所面向的用户

    aud: 接收jwt的一方

    exp: jwt的过期时间,这个过期时间必须要大于签发时间

    nbf: 定义在什么时间之前,该jwt都是不可用的.

    iat: jwt的签发时间

    jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

    公共的声明

    公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.

    私有的声明

    私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

    定义一个payload:

    {"sub":"1234567890","name":"John Doe","admin":true}

    然后将其进行base64加密,得到Jwt的第二部分。

    eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

    signature

    jwt的第三部分是一个签证信息,这个签证信息由三部分组成:

    1.header (base64后的)

    2.payload (base64后的)

    3.secret

    这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

    // javascript

    var  encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);

    var signature = HMACSHA256(encodedString,'secret');

    // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

    将这三部分用.连接成一个完整的字符串,构成了最终的jwt:

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

    注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。

    如何应用

    一般是在请求头里加入Authorization,并加上Bearer标注:

    fetch('api/user/1',{

              headers:{

                        'Authorization':'Bearer '+ token 

                          }

    })

    服务端会验证token,如果验证通过就会返回相应的资源。整个流程就是这样的:

    jwt-diagram

    总结

    优点

    因为json的通用性,所以JWT是可以进行跨语言支持的,像JAVA,JavaScript,NodeJS,PHP等很多语言都可以使用。

    因为有了payload部分,所以JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息。

    便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的。

    它不需要在服务端保存会话信息, 所以它易于应用的扩展

    安全相关

    不应该在jwt的payload部分存放敏感信息,因为该部分是客户端可解密的部分。

    保护好secret私钥,该私钥非常重要。

    如果可以,请使用https协议

    在SpringBoot中整合JWTSpring Security的步奏:

    1.在项目中引入(本项目使用Gradle)

    compile group:'org.springframework.boot',name:'spring-boot-starter-mobile',version:'1.5.4.RELEASE'

    compile group:'org.springframework.boot',name:'spring-boot-starter-security',version:'1.5.4.RELEASE'

    compile group:'io.jsonwebtoken',name:'jjwt',version:'0.7.0'

    2.配置

    目录结构如下:

    WebSecurityConfig文件:

    @SuppressWarnings("SpringJavaAutowiringInspection")

    @Configuration

    @EnableWebSecurity

    @EnableGlobalMethodSecurity(prePostEnabled=true)

    public  class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired

    privateJwtAuthenticationEntryPointunauthorizedHandler;

    @Autowired

     private UserDetailsService userDetailsService;

    @Autowired

    public void configureAuthentication(AuthenticationManagerBuilder  authenticationManagerBuilder) throws Exception {

      authenticationManagerBuilder

             .userDetailsService(this.userDetailsService)

             .passwordEncoder(passwordEncoder());

         }

    @Bean

    public PasswordEncoder passwordEncoder() {

    return new BCryptPasswordEncoder();

        }

    @Bean

    public  JwtAuthenticationTokenFilter authenticationTokenFilterBean()throwsException {

           return newJwtAuthenticationTokenFilter();

         }

    @Override

    protected voidconfigure(HttpSecurity httpSecurity)throwsException {

    httpSecurity

    // we don't need CSRF because our token is invulnerable

    .csrf().disable()

    .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()

    // don't create session

    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

    .authorizeRequests()

    //.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()

    // allow anonymous resource requests

    .antMatchers(

    HttpMethod.GET,

    "/",

    "/*.html",

    "/favicon.ico",

    "/**/*.html",

    "/**/*.css",

    "/**/*.js"

    ).permitAll()

    .antMatchers("/auth/**").permitAll()

    .anyRequest().authenticated();

    // Custom JWT based security filter

    httpSecurity

     .addFilterBefore(authenticationTokenFilterBean(),UsernamePasswordAuthenticationFilter.class);  

      // disable page caching

      httpSecurity.headers().cacheControl();

          }






    相关文章

      网友评论

      • Jetlag时:就解释了jwt Spring Security都没有涉及权限安全的配置 希望作者能通过源码 造福大家
      • 80af1f096564:麻烦提供下源码地址
      • krmao:。。。
        我尽有种虎头蛇尾的感觉

      本文标题:Spring Security 整合 JSON Web Toke

      本文链接:https://www.haomeiwen.com/subject/ohjuhxtx.html