首页 > 编程语言 > 详细

SpringSecurityOAuth2之JWT应用示例

时间:2020-06-14 00:13:47      阅读:71      评论:0      收藏:0      [点我收藏+]

  本文记录一下使用SpringSecurityOAuth2配置JWT的步骤

  1、相关知识

  OAuth协议简介:https://www.cnblogs.com/javasl/p/13054133.html

  OAuth 2.0官网:https://oauth.net/2/

  使用SpringSecurityOAuth2默认实现OAuth2授权示例:https://www.cnblogs.com/javasl/p/13060284.html

  使用SpringSecurityOAuth2配置自定义Token实现OAuth2授权示例:https://www.cnblogs.com/javasl/p/13068613.html

  2、JWT基础

  JWT全称是Json Web Token,它是JSON的一个开放的Token标准。JWT有三个特点:

  1)自包含。JWT中包含着Token有意义的信息,拿到Token,解析后就能知道里面包含的信息是什么,而Spring默认生成的Token是UUID,没有任何有意义的信息。它的信息需要根据这个Token去Redis中读取。

  2)密签。发出去的令牌不包含密码等敏感信息,使用指定的秘钥签名。

  3)可扩展。包含的信息可以根据业务需求自己定义。

  2、构建项目

  本文使用的springboot版本是2.0.4.RELEASE,不同版本可能会有所区别。下面是主要的配置文件和类:

  1)pom依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security.oauth.boot</groupId>
    <artifactId>spring-security-oauth2-autoconfigure</artifactId>
    <version>2.1.3.RELEASE</version>
</dependency>

  2)application.properties

#不需要,暂时写死在代码中,重构时移植到此处即可

  3)主配置类

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .httpBasic()
            .and()
            .csrf().disable();
    }
    
    @Bean("authenticationManager")
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

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

  4)用户认证类

@Component
public class MyUserDetailsService implements UserDetailsService{

    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("登录用户名:"+username);
        String  password = passwordEncoder.encode("123456");
        return new User(username,password,true,true,true,true,
                AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_USER"));
    }
}

  5)认证服务类

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;
    
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
        .accessTokenConverter(jwtAccessTokenConverter)
        .authenticationManager(authenticationManager)
        .userDetailsService(userDetailsService);
    }
    
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients
        .inMemory()
        .withClient("MyProject").secret(passwordEncoder.encode("MyProject_123"))
        .accessTokenValiditySeconds(7200)
        .authorizedGrantTypes("refresh_token","password")
        .scopes("all","read","write");
                
    }
}

  6)JWT配置类

@Configuration
public class JwtTokenConfig {
@Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter(); accessTokenConverter.setSigningKey("shxiang");//设置秘钥 return accessTokenConverter; } }

  7)启动类

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

  4、测试验证

  1)获取Token成功

  技术分享图片

  技术分享图片

  2)将Token复制到https://www.jsonwebtoken.io/解析Token成功 

  技术分享图片

  3)根据Token获取当前用户信息

@GetMapping("/me")
public Object getCurrentUser(Authentication user) {
    return user;
}

  技术分享图片

  技术分享图片

  5、扩展自定义字段 

  1)添加Token增强类

public class MyJwtTokenEnhancer implements TokenEnhancer{

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        Map<String,Object> info = new HashMap<String, Object>();
        info.put("company","test test test");//拓展的字段
        ((DefaultOAuth2AccessToken)accessToken).setAdditionalInformation(info);
        return accessToken;
    }
}

  2)修改JwtTokenConfig.java,添加jwtTokenEnhancer方法创建bean

@Bean
@ConditionalOnMissingBean(name = "jwtTokenEnhancer")
public TokenEnhancer jwtTokenEnhancer() {
    return new MyJwtTokenEnhancer();
}

  3)修改AuthorizationServerConfig.java的configure方法,如下:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{
    ... ...
    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;
    @Autowired
    private TokenEnhancer jwtTokenEnhancer;
    
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
        .authenticationManager(authenticationManager)
        .userDetailsService(userDetailsService);
        
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        List<TokenEnhancer> enhancers = new ArrayList<>();
        enhancers.add(jwtTokenEnhancer);
        enhancers.add(jwtAccessTokenConverter);
        enhancerChain.setTokenEnhancers(enhancers);
        
        endpoints.tokenEnhancer(enhancerChain);
        endpoints.accessTokenConverter(jwtAccessTokenConverter);
    }
    ... ...
}

  测试结果如下:

  技术分享图片

  技术分享图片

  技术分享图片

  注意:拓展的字段不会封装到用户信息Authentication中,执行http://localhost:8080/me不会获取到拓展字段。

  6、获取自定义字段

  1)添加pom.xml依赖

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

  2)测试方法如下

@GetMapping("/me")
public Object getCurrentUser(Authentication user,HttpServletRequest request) throws ExpiredJwtException, UnsupportedJwtException, MalformedJwtException, SignatureException, IllegalArgumentException, UnsupportedEncodingException {
      String header = request.getHeader("Authorization");
      String token = StringUtils.substringAfter(header,"bearer ");
      Claims claims = Jwts.parser().setSigningKey("shxiang".getBytes("UTF-8"))//shxiang是秘钥
                .parseClaimsJws(token).getBody();
      String company = (String)claims.get("company");
      System.out.println("-------company----------:"+company);
      return user;
}

  结果如下:

  技术分享图片

  技术分享图片

  7、Token的刷新

  获取令牌的时候会获取access_token和refresh_token,如下图所示:

  技术分享图片

  使用refresh_token可以刷新Token,如下:

  技术分享图片

  技术分享图片

  当用户使用Token访问时,发现超时了,在无感知的情况下立马使用refresh_token请求一个新的Token。refresh_token设置较长时间,如:

.accessTokenValiditySeconds(7200)
.refreshTokenValiditySeconds(2592000)

 

SpringSecurityOAuth2之JWT应用示例

原文:https://www.cnblogs.com/javasl/p/13122273.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!