最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用SpringSecurity 進(jìn)行自定義Token校驗(yàn)

 更新時(shí)間:2021年06月23日 09:59:47   作者:TerrellChen  
這篇文章主要介紹了使用SpringSecurity 進(jìn)行自定義Token校驗(yàn)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

背景

Spring Security默認(rèn)使用「用戶名/密碼」的方式進(jìn)行登陸校驗(yàn),并通過(guò)cookie的方式存留登陸信息。在一些定制化場(chǎng)景,比如希望單獨(dú)使用token串進(jìn)行部分頁(yè)面的訪問(wèn)權(quán)限控制時(shí),默認(rèn)方案無(wú)法支持。

在未能在網(wǎng)上搜索出相關(guān)實(shí)踐的情況下,通過(guò)官方文檔及個(gè)別Stack Overflow的零散案例,形成整體思路并實(shí)踐測(cè)試通過(guò),本文即關(guān)于該方案的一個(gè)分享。

參考官方文檔

SpringSecurity校驗(yàn)流程

基本的SpringSecurity使用方式網(wǎng)上很多,不是本文關(guān)注的重點(diǎn)。

關(guān)于校驗(yàn)的整個(gè)流程簡(jiǎn)單的說(shuō),整個(gè)鏈路有三個(gè)關(guān)鍵點(diǎn),

  • 將需要鑒權(quán)的類(lèi)/方法/url),定義為需要鑒權(quán)(本文代碼示例為方法上注解@PreAuthorize("hasPermission('TARGET','PERMISSION')")
  • 根據(jù)訪問(wèn)的信息產(chǎn)生一個(gè)來(lái)訪者的權(quán)限信息Authentication,并插入到上下文中
  • 在調(diào)用鑒權(quán)方法時(shí),根據(jù)指定的鑒權(quán)方式,驗(yàn)證權(quán)限信息是否符合權(quán)限要求

完整的調(diào)用鏈建議在IDE中通過(guò)單步調(diào)試親自體會(huì),本文不做相關(guān)整理。

如何自定義

我的需求,是使用自定義的token,驗(yàn)證權(quán)限,涉及到:

  • 產(chǎn)生Authentication并插入到上下文中
  • 針對(duì)token的驗(yàn)證方式

需要做的事情如下:

  • 自定義TokenAuthentication類(lèi),實(shí)現(xiàn)org.springframework.security.core.Authenticaion,作為token權(quán)限信息
  • 自定義AuthenticationTokenFilter類(lèi),實(shí)現(xiàn)javax.servlet.Filter,在收到訪問(wèn)時(shí),根據(jù)訪問(wèn)信息生成TokenAuthentication實(shí)例,并插入上下文
  • 自定義SecurityPermissionEvalutor類(lèi),實(shí)現(xiàn)org.springframework.security.access.PermissionEvaluator,完成權(quán)限的自定義驗(yàn)證邏輯
  • 在全局的配置中,定義使用SecurityPermissionEvalutor作為權(quán)限校驗(yàn)方式

TokenAuthentication.java

/**
 * @author: Blaketairan
 */
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import java.util.ArrayList;
import java.util.Collection;
/**
 * Description: spring-security的Authentication的自定義實(shí)現(xiàn)(用于校驗(yàn)token)
 */
public class TokenAuthentication implements Authentication{
    private String token;
    public TokenAuthentication(String token){
        this.token = token;
    }
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return new ArrayList<GrantedAuthority>(0);
    }
    @Override
    public Object getCredentials(){
        return token;
    }
    @Override
    public Object getDetails() {
        return null;
    }
    @Override
    public Object getPrincipal() {
        return null;
    }
    @Override
    public boolean isAuthenticated() {
        return true;
    }
    @Override
    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
    }
    @Override
    public String getName() {
        return null;
    }
}

AuthenticationTokenFilter.java

/**
 * @author: Blaketairan
 */
import com.google.common.base.Strings;
import com.blaketairan.spring.security.configuration.TokenAuthentication;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
 * Description: 用于處理收到的token并為spring-security上下文生成及注入Authenticaion實(shí)例
 */
@Configuration
public class AuthenticationTokenFilter implements Filter{
    @Override
    public void init(FilterConfig filterConfig) throws ServletException{
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,FilterChain filterChain)
            throws IOException, ServletException{
        if (servletRequest instanceof HttpServletRequest){
            String token = ((HttpServletRequest) servletRequest).getHeader("PRIVATE-TOKEN");
            if (!Strings.isNullOrEmpty(token)){
                Authentication authentication = new TokenAuthentication(token);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                System.out.println("Set authentication with non-empty token");
            } else {
                /**
                 * 在未收到Token時(shí),至少塞入空TokenAuthenticaion實(shí)例,避免進(jìn)入SpringSecurity的用戶名密碼默認(rèn)模式
                 */
                Authentication authentication = new TokenAuthentication("");
                SecurityContextHolder.getContext().setAuthentication(authentication);
                System.out.println("Set authentication with empty token");
            }
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }
    @Override
    public void destroy(){
    }
}

SecurityPermissionEvalutor.java

/**
 * @author: Blaketairan
 */
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import java.io.Serializable;
/**
 * Description: spring-security 自定義的權(quán)限處理模塊(鑒權(quán))
 */
public class SecurityPermissionEvaluator implements PermissionEvaluator {
    @Override
    public boolean hasPermission(Authentication authentication,Object targetDomainObject, Object permission){
        String targetDomainObjectString = null;
        String permissionString = null;
        String token = null;
        try {
            targetDomainObjectString = (String)targetDomainObject;
            permissionString = (String)permission;
            token = (String)authentication.getCredentials();
        } catch (ClassCastException e){
            e.printStackTrace();
            return false;
        }
        return hasPermission(token, targetDomainObjectString, permissionString);
    }
    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission){
        /**
         * 使用@PreAuthorize("hasPermission('TARGET','PERMISSION')")方式,不使用該鑒權(quán)邏輯
         */
        return false;
    }
    private boolean hasPermission(String token,String targetDomain, String permission){
        /**
         * 驗(yàn)證權(quán)限
        **/
        return true;
    }
}

SecurityConfig.java 全局配置

/**
 * @author: Blaketairan
 */
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
 * Description: spring-security配置,指定使用自定義的權(quán)限評(píng)估方法
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter{
    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception{
        return super.authenticationManager();
    }
    @Bean
    public PermissionEvaluator permissionEvaluator() {
        /**
         * 使用自定義的權(quán)限驗(yàn)證
        **/
        SecurityPermissionEvaluator securityPermissionEvaluator = new SecurityPermissionEvaluator();
        return securityPermissionEvaluator;
    }
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception{
        /**
         * 關(guān)掉csrf方便本地ip調(diào)用調(diào)試
        **/
        httpSecurity
                .csrf()
                .disable()
                .httpBasic()
                .disable();
    }
}

BaseRepository.java 某個(gè)需要權(quán)限驗(yàn)證的方法

/**
 * @author: Blaketairan
 */
import org.springframework.security.access.prepost.PreAuthorize;
import java.util.List;
/**
 * Description: 
 */
public interface BaseRepository{
    @PreAuthorize("hasPermission('DOMAIN', 'PERMISSION')")
    void deleteAll();
}

spring security 自定義token無(wú)法通過(guò)框架認(rèn)證

自定義token和refreshToken,如代碼所示:

UserDO userDO = userMapper.getByName(username);
UserDetails userDetails = 
userService.loadUserByUsername(userForBase.getName());
String token = jwtTokenComponent.generateToken(userDO);
String refreshToken = jwtTokenComponent.generateRefreshToken(userDO);
storeToken(userDO, token,refreshToken);
jsonObject.put("principal", userDetails);
jsonObject.put("token_type", "bearer");
return jsonObject;

無(wú)法通過(guò)框架的認(rèn)證?搞它:

UserDO userDO = userMapper.getByName(username);
UserDetails userDetails = 
userService.loadUserByUsername(userForBase.getName());
String token = jwtTokenComponent.generateToken(userDO);
String refreshToken = jwtTokenComponent.generateRefreshToken(userDO);
storeToken(userDO, token,refreshToken);
jsonObject.put("access_token", token);
jsonObject.put("refresh_token", refreshToken);
jsonObject.put("principal", userDetails);
jsonObject.put("token_type", "bearer");
return jsonObject;
private void storeToken(UserDO userDO, String token,String refreshToken) {
        Map<String, String> tokenParams = new HashMap<>();
        tokenParams.put("access_token", token);
        tokenParams.put("expires_in", "7200");
        tokenParams.put("token_type", "bearer");
        OAuth2AccessToken oAuth2AccessToken = DefaultOAuth2AccessToken.valueOf(tokenParams);
        DefaultOAuth2RefreshToken oAuth2RefreshToken = new DefaultOAuth2RefreshToken(refreshToken);
        // 創(chuàng)建redisTemplate,序列化對(duì)象
        Map<String, String> requestMap = new HashMap<>();
        requestMap.put("username", userDO.getUsername());
        requestMap.put("grant_type", "password");
        Map<String, Object> queryMap = new HashMap<String, Object>();
        queryMap.put("id",userDO.getUserId());
        List<String> perms = menuMapper.listUserPerms(queryMap);
        Set<GrantedAuthority> authorities = new HashSet<>();
        for (String perm : perms) {
if (StringUtils.isNotBlank(perm)) {
    authorities.add(new SimpleGrantedAuthority(perm.trim()));
}
        }
        OAuth2Request storedRequest = new OAuth2Request(requestMap, "oms-web", authorities, true, null,
    null, null, null, null);
        CustomUserDetails userEnhancer = new CustomUserDetails(userDO, true, true, true, true, authorities);
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userEnhancer, null, userEnhancer.getAuthorities());
        authentication.setDetails(requestMap);
        OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(storedRequest, authentication);
        tokenStore.storeAccessToken(oAuth2AccessToken, oAuth2Authentication);
        tokenStore.storeRefreshToken(oAuth2RefreshToken, oAuth2Authentication);
    }

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java抽象的本質(zhì)解析

    Java抽象的本質(zhì)解析

    對(duì)于面向?qū)ο缶幊虂?lái)說(shuō),抽象是它的一大特征之一,在 Java 中可以通過(guò)兩種形式來(lái)體現(xiàn)OOP的抽象:接口和抽象類(lèi),下面這篇文章主要給大家介紹了關(guān)于Java基礎(chǔ)抽象的相關(guān)資料,需要的朋友可以參考下
    2022-03-03
  • JVM常用垃圾收集器及GC算法解讀

    JVM常用垃圾收集器及GC算法解讀

    這篇文章主要介紹了JVM常用垃圾收集器及GC算法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • springboot+mybatis報(bào)錯(cuò)找不到實(shí)體類(lèi)的問(wèn)題

    springboot+mybatis報(bào)錯(cuò)找不到實(shí)體類(lèi)的問(wèn)題

    這篇文章主要介紹了springboot+mybatis報(bào)錯(cuò)找不到實(shí)體類(lèi)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • 詳解SpringMVC驗(yàn)證框架Validation特殊用法

    詳解SpringMVC驗(yàn)證框架Validation特殊用法

    本篇文章主要介紹了詳解SpringMVC驗(yàn)證框架Validation特殊用法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-02-02
  • Java?OpenCV學(xué)習(xí)之Mat的基本操作詳解

    Java?OpenCV學(xué)習(xí)之Mat的基本操作詳解

    OpenCV用來(lái)存儲(chǔ)圖像,很多時(shí)候都會(huì)用到這個(gè)Mat方法。數(shù)字圖像可看做一個(gè)數(shù)值矩陣,?其中的每一個(gè)元素表明一個(gè)像素點(diǎn)。Mat在?OpenCV?中表示的是?N?維稠密矩陣,與稠密矩陣相對(duì)的是稀疏矩陣。本文將重點(diǎn)介紹OpenCV中Mat的一些基本操作,需要的可以參考一下
    2022-03-03
  • Java深入學(xué)習(xí)圖形用戶界面GUI之事件處理

    Java深入學(xué)習(xí)圖形用戶界面GUI之事件處理

    這篇文章主要介紹了基于Java GUI 事件處理方式,一個(gè)圖形界面制作完成了,在程序開(kāi)發(fā)中只是完成了起步的工作。要想讓一個(gè)組件都發(fā)揮自己的作用.就必須對(duì)所有的組件進(jìn)行事件處理
    2022-05-05
  • Java基于TCP協(xié)議的Socket通信

    Java基于TCP協(xié)議的Socket通信

    本文詳細(xì)講解了Java基于TCP協(xié)議的Socket通信,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • String轉(zhuǎn)BigDecimal,BigDecimal常用操作,以及避免踩坑記錄

    String轉(zhuǎn)BigDecimal,BigDecimal常用操作,以及避免踩坑記錄

    這篇文章主要介紹了String轉(zhuǎn)BigDecimal,BigDecimal常用操作,以及避免踩坑記錄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Java Long類(lèi)型對(duì)比分析

    Java Long類(lèi)型對(duì)比分析

    這篇文章主要介紹了Java Long類(lèi)型對(duì)比分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • MybatisPlus關(guān)聯(lián)查詢的完美實(shí)現(xiàn)方案

    MybatisPlus關(guān)聯(lián)查詢的完美實(shí)現(xiàn)方案

    我們?cè)陧?xiàng)目開(kāi)發(fā)的時(shí)候,難免會(huì)遇到連表查詢的操作,所以下面這篇文章主要給大家介紹了關(guān)于MybatisPlus關(guān)聯(lián)查詢的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-12-12

最新評(píng)論

南昌县| 江油市| 荥阳市| 方城县| 包头市| 积石山| 叶城县| 宁化县| 岚皋县| 扎兰屯市| 腾冲县| 华安县| 高要市| 务川| 怀远县| 贵州省| 林口县| 新邵县| 金秀| 虹口区| 英德市| 浙江省| 阳朔县| 呼伦贝尔市| 平果县| 巴中市| 镇康县| 贵定县| 芒康县| 合阳县| 武夷山市| 威远县| 马龙县| 盐源县| 深水埗区| 新疆| 抚顺市| 平遥县| 永春县| 顺义区| 紫云|