中文字幕精品亚洲无线码二区,国产黄a三级三级三级看三级,亚洲七七久久桃花影院,丰满少妇被猛烈进入,国产小视频在线观看网站

spring-security實現的token授權

在我的用戶密碼授權文章里介紹了spring-security的工作過程,不了解的同學,可以先看看用戶密碼授權這篇文章,在
用戶密碼授權模式里,主要是通過一個登陸頁進行授權,然后把授權對象寫到session里,它主要用在mvc框架里,而對于webapi來說,一般不會采用這種方式,對于webapi
來說,一(yi)(yi)般會(hui)用jwt授(shou)權(quan)方(fang)式,就是token授(shou)權(quan)碼的(de)方(fang)式,每訪問(wen)api接(jie)口時,在http頭上帶著你(ni)的(de)token碼,而大叔自己也(ye)寫了一(yi)(yi)個簡單的(de)jwt授(shou)權(quan)模式,下(xia)面(mian)介紹(shao)一(yi)(yi)下(xia)。

WebSecurityConfig授權配置

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {
  /**
   * token過濾器.
   */
  @Autowired
  LindTokenAuthenticationFilter lindTokenAuthenticationFilter;

  @Bean
  @Override
  public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
  }

  @Override
  protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
        .csrf().disable()
        // 基于token,所以不需要session
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
        .authorizeRequests()
        // 對于獲取token的rest api要允許匿名訪問
        .antMatchers("/lind-auth/**").permitAll()
        // 除上面外的所有請求全部需要鑒權認證
        .anyRequest().authenticated();
    httpSecurity
        .addFilterBefore(lindTokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
    // 禁用緩存
    httpSecurity.headers().cacheControl();
  }

  /**
   * 密碼生成策略.
   *
   * @return
   */
  @Bean
  public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }
}

授權接口login

對外開放的,需要提供用戶名和密碼為參數進行登陸,然后返回token碼,當然也可以使用手機號和驗證碼登陸,授權邏輯是一樣的,獲取用戶信息都是使用UserDetailsService,
然后開發人員根據自己的業務去重寫loadUserByUsername來獲取用戶實體。

用戶(hu)登陸成功(gong)后,為它授權及認證(zheng),這一步(bu)我(wo)們會(hui)在redis里建立token與用戶(hu)名的關系。

@GetMapping(LOGIN)
  public ResponseEntity<?> refreshAndGetAuthenticationToken(
      @RequestParam String username,
      @RequestParam String password) throws AuthenticationException {
    return ResponseEntity.ok(generateToken(username, password));
  }

  /**
   * 登陸與授權.
   *
   * @param username .
   * @param password .
   * @return
   */
  private String generateToken(String username, String password) {
    UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password);
    // Perform the security
    final Authentication authentication = authenticationManager.authenticate(upToken);
    SecurityContextHolder.getContext().setAuthentication(authentication);
    // Reload password post-security so we can generate token
    final UserDetails userDetails = userDetailsService.loadUserByUsername(username);
    // 持久化的redis
    String token = CommonUtils.encrypt(userDetails.getUsername());
    redisTemplate.opsForValue().set(token, userDetails.getUsername());
    return token;
  }

LindTokenAuthenticationFilter代碼

主要實現了對請求的攔截,獲取http頭上的Authorization元素,token碼就在這個鍵里,我們的token都是采用通用的Bearer開頭,當你的token沒有過期時,會
存(cun)(cun)儲在redis里,key就(jiu)是用(yong)戶名(ming)的(de)md5碼,而value就(jiu)是用(yong)戶名(ming),當(dang)拿到token之后去數(shu)據庫(ku)或者緩存(cun)(cun)里拿用(yong)戶信息進行授權(quan)即可。

/**
 * token filter bean.
 */
@Component
public class LindTokenAuthenticationFilter extends OncePerRequestFilter {

  @Autowired
  RedisTemplate<String, String> redisTemplate;
  String tokenHead = "Bearer ";
  String tokenHeader = "Authorization";
  @Autowired
  private UserDetailsService userDetailsService;

  /**
   * token filter.
   *
   * @param request     .
   * @param response    .
   * @param filterChain .
   */
  @Override
  protected void doFilterInternal(
      HttpServletRequest request,
      HttpServletResponse response,
      FilterChain filterChain) throws ServletException, IOException {

    String authHeader = request.getHeader(this.tokenHeader);
    if (authHeader != null && authHeader.startsWith(tokenHead)) {
      final String authToken = authHeader.substring(tokenHead.length()); // The part after "Bearer "
      if (authToken != null && redisTemplate.hasKey(authToken)) {
        String username = redisTemplate.opsForValue().get(authToken);
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
          UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
          //可以校驗token和username是否有效,目前由于token對應username存在redis,都以默認都是有效的
          UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
              userDetails, null, userDetails.getAuthorities());
          authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(
              request));
          logger.info("authenticated user " + username + ", setting security context");
          SecurityContextHolder.getContext().setAuthentication(authentication);
        }
      }
    }

    filterChain.doFilter(request, response);

  }

測試token授權

get://localhost:8080/lind-demo/login?username=admin&password=123

post://localhost:8080/lind-demo/user/add
Content-Type:application/json
Authorization:Bearer 21232F297A57A5A743894A0E4A801FC3
posted @ 2019-03-15 17:49  張占嶺  閱讀(40672)  評論(1)    收藏  舉報