基于SpringBoot整合oauth2实现token认证

前端之家收集整理的这篇文章主要介绍了基于SpringBoot整合oauth2实现token认证前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

这篇文章主要介绍了基于SpringBoot整合oauth2实现token 认证,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

session和token的区别:

@H_404_6@
  • session是空间换时间,而token是时间换空间。session占用空间,但是可以管理过期时间,token管理部了过期时间,但是不占用空间.
  • sessionId失效问题和token内包含。
  • session基于cookie,app请求并没有cookie 。
  • token更加安全(每次请求都需要带上)
  • Oauth2 密码授权流程

    在oauth2协议里,每一个应用都有自己的一个clientId和clientSecret(需要去认证方申请),所以一旦想通过认证,必须要有认证方下发的clientId和secret。

    基于SpringBoot整合oauth2实现token认证

    1. pom

    <!--security-->
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
          <groupId>org.springframework.security.oauth</groupId>
          <artifactId>spring-security-oauth2</artifactId>
        </dependency>

    2. UserDetail实现认证第一步

    MyUserDetailsService.java

    @Autowired
      private PasswordEncoder passwordEncoder;
    
      /**
       * 根据进行登录
       * @param username
       * @return
       * @throws UsernameNotFoundException
       */
      @Override
      public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        log.info("登录用户名:"+username);
        String password = passwordEncoder.encode("123456");
        //User三个参数  (用户名+密码+权限)
        //根据查找到的用户信息判断用户是否被冻结
        log.info("数据库密码:"+password);
        return new User(username,password,AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
      }

    3. 获取token的控制器

    @RestController
    public class OauthController {
    
      @Autowired
      private ClientDetailsService clientDetailsService;
      @Autowired
      private AuthorizationServerTokenServices authorizationServerTokenServices;
      @Autowired
      private AuthenticationManager authenticationManager;
    
      @PostMapping("/oauth/getToken")
      public Object getToken(@RequestParam String username,@RequestParam String password,HttpServletRequest request) throws IOException {
        Map<String,Object>map = new HashMap<>(8);
        //进行验证
        String header = request.getHeader("Authorization");
        if (header == null && !header.startsWith("Basic")) {
          map.put("code",500);
          map.put("message","请求投中无client信息");
          return map;
        }
        String[] tokens = this.extractAndDecodeHeader(header,request);
        assert tokens.length == 2;
        //获取clientId 和 clientSecret
        String clientId = tokens[0];
        String clientSecret = tokens[1];
        //获取 ClientDetails
        ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
        if (clientDetails == null){
          map.put("code","clientId 不存在"+clientId);
          return map;
          //判断 方言 是否一致
        }else if (!StringUtils.equals(clientDetails.getClientSecret(),clientSecret)){
          map.put("code","clientSecret 不匹配"+clientId);
          return map;
        }
        //使用username、密码进行登录
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username,password);
        //调用指定的UserDetailsService,进行用户名密码验证
        Authentication authenticate = authenticationManager.authenticate(authentication);
        HrUtils.setCurrentUser(authenticate);
        //放到session中
        //密码授权 模式,组建 authentication
        TokenRequest tokenRequest = new TokenRequest(new HashMap<>(),clientId,clientDetails.getScope(),"password");
    
        OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);
        OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request,authentication);
    
        OAuth2AccessToken token = authorizationServerTokenServices.createAccessToken(oAuth2Authentication);
        map.put("code",200);
        map.put("token",token.getValue());
        map.put("refreshToken",token.getRefreshToken());
        return map;
      }
    
      /**
       * 解码请求头
       */
      private String[] extractAndDecodeHeader(String header,HttpServletRequest request) throws IOException {
        byte[] base64Token = header.substring(6).getBytes("UTF-8");
    
        byte[] decoded;
        try {
          decoded = Base64.decode(base64Token);
        } catch (IllegalArgumentException var7) {
          throw new BadCredentialsException("Failed to decode basic authentication token");
        }
    
        String token = new String(decoded,"UTF-8");
        int delim = token.indexOf(":");
        if (delim == -1) {
          throw new BadCredentialsException("Invalid basic authentication token");
        } else {
          return new String[]{token.substring(0,delim),token.substring(delim + 1)};
        }
      }
    }

    4. 核心配置

    (1)、Security 配置类 说明登录方式、登录页面、哪个url需要认证、注入登录失败/成功过滤器

    @Configuration
    public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
    
      /**
       * 注入 自定义登录成功处理类
       */
      @Autowired
      private MyAuthenticationSuccessHandler mySuccessHandler;
      /**
       * 注入 自定义登录失败处理类
       */
      @Autowired
      private MyAuthenticationFailHandler myFailHandler;
    
      @Autowired
      private ValidateCodeFilter validateCodeFilter;
    
      /**
       * 重写PasswordEncoder 接口中的方法,实例化加密策略
       * @return 返回 BCrypt 加密策略
       */
      @Bean
      public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
      }
    
      @Override
      protected void configure(HttpSecurity http) throws Exception {
        //在UsernamePasswordAuthenticationFilter 过滤器前 加一个过滤器 来搞验证码
        http.addFilterBefore(validateCodeFilter,UsernamePasswordAuthenticationFilter.class)
            //表单登录 方式
            .formLogin()
            .loginPage("/authentication/require")
            //登录需要经过的url请求
            .loginProcessingUrl("/authentication/form")
            .passwordParameter("pwd")
            .usernameParameter("user")
            .successHandler(mySuccessHandler)
            .failureHandler(myFailHandler)
            .and()
            //请求授权
            .authorizeRequests()
            //不需要权限认证的url
            .antMatchers("/oauth/*","/authentication/*","/code/image").permitAll()
            //任何请求
            .anyRequest()
            //需要身份认证
            .authenticated()
            .and()
            //关闭跨站请求防护
            .csrf().disable();
        //默认注销地址:/logout
        http.logout().
            //注销之后 跳转页面
            logoutSuccessUrl("/authentication/require");
      }
    
      /**
       * 认证管理
       *
       * @return 认证管理对象
       * @throws Exception 认证异常信息
       */
      @Override
      @Bean
      public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
      }
    }

    (2)、认证服务器

    @Configuration
    @EnableAuthorizationServer
    public class MyAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
      @Autowired
      private AuthenticationManager authenticationManager;
    
      @Autowired
      private MyUserDetailsService userDetailsService;
    
      @Override
      public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        super.configure(security);
      }
    
      /**
       * 客户端配置(给谁发令牌)
       * @param clients
       * @throws Exception
       */
      @Override
      public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory().withClient("internet_plus")
            .secret("internet_plus")
            //有效时间 2小时
            .accessTokenValiditySeconds(72000)
            //密码授权模式和刷新令牌
            .authorizedGrantTypes("refresh_token","password")
            .scopes( "all");
      }
    
      @Override
      public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
            .authenticationManager(authenticationManager)
            .userDetailsService(userDetailsService);
      }
    }

    @EnableResourceServer这个注解就决定了这是个资源服务器。它决定了哪些资源需要什么样的权限。

    5、测试

    基于SpringBoot整合oauth2实现token认证

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

    猜你在找的Springboot相关文章