spring boot + spring Security + redis token 思路爬坡


spring boot + spring Security + redis + token 爬坡

分為幾個部分 spring boot 基本配置 controller接口部分  安全校驗部分(包括session或者自定義token的形式) redis的token存放與取出  , 數據庫校驗

spring boot 基本配置

pom和啟動類

https://www.cnblogs.com/funkboy/p/12889708.html     pom的jar版本要一一對應,不要產生spring沖突

application.yml 和 properties 配置

https://www.cnblogs.com/luzhanshi/p/10597641.html  like this

 

實現檢驗思路

Security 部分

兩種思路,

第一種

一種是spring Security只負責校驗 ,生成和存儲token的部分放在controller里

這種情況只需要

WebSecurityConfigurer extends WebSecurityConfigurerAdapter 
configure:
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); // JWT Filter 校驗部分
在登錄的接口配置權限
@PreAuthorize("hasAuthority('ddd:list')")

 filter部分

package com.lzw.security.filter;

import com.alibaba.fastjson.JSON;
import com.lzw.security.common.GenericResponse;
import com.lzw.security.common.ServiceError;
import com.lzw.security.entity.User;
import com.lzw.security.service.SelfUserDetailsService;
import com.lzw.security.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Set;

/**
 * @author: jamesluozhiwei 組2
 * @description: 確保在一次請求只通過一次filter,而不需要重復執行  被springboot security 主類 調用
 */
@Component
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Value("${token.expirationMilliSeconds}")
    private long expirationMilliSeconds;

    @Autowired
    SelfUserDetailsService userDetailsService;

    @Autowired
    RedisUtil redisUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
       //?
        String authHeader = request.getHeader("Authorization");
        response.setCharacterEncoding("utf-8");
        if (null == authHeader || !authHeader.startsWith("Bearer ")){
            filterChain.doFilter(request,response);//token格式不正確
            return;
        }
        String authToken = authHeader.substring("Bearer ".length());

        String subject = JwtTokenUtil.parseToken(authToken);//獲取在token中自定義的subject,用作用戶標識,用來獲取用戶權限

        //獲取redis中的token信息

        if (!redisUtil.hasKey(authToken)){
            //token 不存在 返回錯誤信息
            response.getWriter().write(JSON.toJSONString(GenericResponse.response(ServiceError.GLOBAL_ERR_NO_SIGN_IN)));
            return;
        }

        //獲取緩存中的信息(根據自己的業務進行拓展)
        HashMap<String,Object> hashMap = (HashMap<String, Object>) redisUtil.hget(authToken);
        //從tokenInfo中取出用戶信息   ********
        User user = new User();
        user.setId(Long.parseLong(hashMap.get("id").toString())).setAuthorities((Set<? extends GrantedAuthority>) hashMap.get("authorities"));
        if (null == hashMap){
            //用戶信息不存在或轉換錯誤,返回錯誤信息
            response.getWriter().write(JSON.toJSONString(GenericResponse.response(ServiceError.GLOBAL_ERR_NO_SIGN_IN)));
            return;
        }
        //更新token過期時間
        redisUtil.setKeyExpire(authToken,expirationMilliSeconds);
        //將信息交給security  *******
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user,null,user.getAuthorities());
        authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        filterChain.doFilter(request,response);
    }
}

 

第二種

另一種全部托管於spring Security

 mian class
WebSecurityConfigurer extends WebSecurityConfigurerAdapter 

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .userDetailsService(customUserDetailsService) .passwordEncoder(passwordEncoder()); } 設置查詢方法 customUserDetailsService: //數據庫查信息實現 UserDetailsService @Component public class CustomUserDetailsService implements UserDetailsService passwordEncoder() @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
xxxxxxxxxxx
return user;
}
把放入token到redis的任務賦給handler
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler

在filter里

先把token和用戶權限存放到redis
並且
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
...
 @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
...
 UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user,null,user.getAuthorities());
        authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        filterChain.doFilter(request,response);

 Redis token 部分

在頁面調用登錄接口時校驗 如果數據正確 生成一組redis數據 包含username 權限組 token 等 ,返回token串,接下來所有的請求就要帶上這個token ,如果請求符合這個token所代表的用戶就放行,如果不符合就會被token過濾,返回失敗handler

 

與前端交互

 做好與前端協調,可選全json的數據交換,也可用post body 傳值 

post 請求

獲取值 https://blog.csdn.net/qq_41665356/article/details/80234392

可以用string vo形參和httprequest獲取

postman 介紹

https://www.cnblogs.com/zhuxr/p/9009708.html

 附贈小提示

controller接口部分

@RestController/Controller  注入   @RequestMapping 等 獲取請求與返回

   spring PreAuthorize 配置  https://blog.csdn.net/weixin_39220472/article/details/80873268  

    @RequestMapping("/info/{id}") 參數restful
    @PreAuthorize("hasRole('sys:config:info')") 權限校驗
    public R info(@PathVariable("id") Long id){
        SysConfig config = sysConfigService.getById(id);

        return R.ok().put("config", config);
    }
value:  指定請求的實際地址, 比如 /action/info之類。
method:  指定請求的method類型, GET、POST、PUT、DELETE等
consumes: 指定處理請求的提交內容類型(Content-Type),例如application/json, text/html;
produces:    指定返回的內容類型,僅當request請求頭中的(Accept)類型中包含該指定類型才返回
params: 指定request中必須包含某些參數值是,才讓該方法處理
headers: 指定request中必須包含某些指定的header值,才能讓該方法處理請求

R: 一個vo 

 

 

spring security 爬坡

主要類分析

public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter

Security主體類 功能實現基礎

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {

自定義安全校驗 --> AuthenticationManagerBuilder
用於創建AuthenticationManager的SecurityBuilder。允許輕松構建內存身份驗證,LDAP身份驗證,基於JDBC的身份驗證,添加UserDetailsS​​ervice以及添加AuthenticationProvider。

auth.userDetailsService(customUserDetailsService) customUserDetailsService 這是一個繼承UserDetailsService 的Component 重寫方法loadUserByUsername 在數據庫里校驗身份

protected void configure(HttpSecurity http) {  過濾的主方法,核心
antMatchers(urls[String 數組]) 放行的url 數組

.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) 關閉session
csrf()
Adds CSRF support. This is activated by default when using WebSecurityConfigurerAdapter's default constructor. You can disable it using:
 @Configuration
 @EnableWebSecurity
 public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() ...; } } Returns: the CsrfConfigurer for further customizations Throws: java.lang.Exception

 



! 在所有filter 之前

addFilterBefore
public HttpSecurity addFilterBefore(javax.servlet.Filter filter, java.lang.Class<? extends javax.servlet.Filter> beforeFilter) Description copied from interface: HttpSecurityBuilder Allows adding a Filter before one of the known Filter classes. The known Filter instances are either a Filter listed in HttpSecurityBuilder.addFilter(Filter) or a Filter that has already been added using HttpSecurityBuilder.addFilterAfter(Filter, Class) or HttpSecurityBuilder.addFilterBefore(Filter, Class). Specified by: addFilterBefore in interface HttpSecurityBuilder<HttpSecurity> Parameters: filter - the Filter to register before the type beforeFilter beforeFilter - the Class of the known Filter. Returns: the HttpSecurity for further customizations
這個是所有的訪問都要過一下在這加過濾token的code

@SneakyThrows
lombok 甩出所有的錯誤
@EnableWebSecurity
https://blog.csdn.net/andy_zhang2007/article/details/90023901
該注解其實起到了如下效果 :

控制Spring Security是否使用調試模式(通過注解屬性debug指定),缺省為false,表示缺省不使用調試模式;
導入 WebSecurityConfiguration,用於配置Web安全過濾器FilterChainProxy;
若干個WebSecurityConfigurerAdapter作用於一個WebSecurity生成一個最終使用的web安全過濾器FilterChainProxy
如果是Servlet 環境,導入WebMvcSecurityConfiguration;
如果是OAuth2環境,導入OAuth2ClientConfiguration;
使用注解@EnableGlobalAuthentication啟用全局認證機制
————————————————
版權聲明:本文為CSDN博主「安迪源文」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/andy_zhang2007/article/details/90023901

關於 @EnableGlobalMethodSecurity 開啟spring 

https://www.cnblogs.com/520playboy/p/7286085.html

@bean

注入實例到spring 工廠中以便於@Autowired等獲取

 

沒寫完呢


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM