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

SpringSecurity和jwt實現(xiàn)登錄及權(quán)限認證功能

 更新時間:2025年11月27日 09:26:58   作者:q***7219  
本文介紹了如何使用SpringSecurity和JWT實現(xiàn)系統(tǒng)的登錄和權(quán)限控制,包括JWT的工作原理、RBAC角色權(quán)限管理、數(shù)據(jù)庫設(shè)計、攔截器實現(xiàn)、登錄接口和權(quán)限驗證的代碼示例,感興趣的朋友跟隨小編一起看看吧

系列文章目錄

spring security+jwt安全方案

前言

前面我們已經(jīng)通過使用springboot框架獲得了管理數(shù)據(jù)的基本能力,但是一個系統(tǒng)不和或缺的功能是安全登錄。
這里我們以springsecurity+jwt方案實現(xiàn)登錄以及權(quán)限控制。

一、springsecurity+jwt方案

提示:這里是對該方案的原理簡介
一個安全的系統(tǒng)是需要對請求身份進行認證的。

但是http協(xié)議是無狀態(tài)的,所以需要對每次的請求進行校驗。

以下是jwt方案流程圖,我們以現(xiàn)實生活為例。當(dāng)我們被一個學(xué)校錄取,我們在開學(xué)的時候需要提供身份證(類比賬號密碼),學(xué)校就會發(fā)放一個學(xué)生證(類比jwt令牌),這樣我們每次進學(xué)校帶學(xué)生證就行了(每次使用系統(tǒng)帶jwt就行了)

二、權(quán)限控制RBAC

提示:這里是對登錄的細化,即權(quán)限功能
登錄系統(tǒng)的人并不只是一個人,以下為RBAC的數(shù)據(jù)庫設(shè)計圖。

我們依然以現(xiàn)實世界為例,一個教務(wù)系統(tǒng),有很多用戶(user);其中有兩種身份(role):老師和學(xué)生;老師和學(xué)生擁有不一樣的功能(menu),老師可以改卷子打分等等。

三、實現(xiàn)

我們以該圖為例,該流程即為需要實現(xiàn)的。

1.RBAC數(shù)據(jù)庫實現(xiàn)

這里請自行搜索RBAC的sql代碼

2.攔截器實現(xiàn)

給系統(tǒng)套上一層攔截功能即是security實現(xiàn)的功能,這里先實現(xiàn)接口放行
在maven添加以下依賴后:

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

系統(tǒng)會自動生成一個登錄頁面,我們需要做的就是給登錄接口放行,其他接口攔截的配置
參考以下配置

package com.nie.sportserver.config;
import com.nie.sportserver.Interceptor.JwtTokenAdminInterceptor;
import com.nie.sportserver.exception.MyAccessDeniedHandler;
import com.nie.sportserver.exception.MyAuthenticationEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.time.Duration;
import java.util.Arrays;
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    MyAccessDeniedHandler myAccessDeniedHandler;
    @Autowired
    MyAuthenticationEntryPoint myAuthenticationEntryPoint;
    @Autowired
    JwtTokenAdminInterceptor jwtTokenAdminInterceptor;
    //加密算法
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    //security配置跨域
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOriginPattern("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.setAllowCredentials(true);
        source.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(source);
    }
    //配置安全攔截
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()//關(guān)閉csrf
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                //不通過Session獲取Securitycontext
                .and()//配置異常處理
                .exceptionHandling()
                .authenticationEntryPoint(myAuthenticationEntryPoint)
                .accessDeniedHandler(myAccessDeniedHandler)
                .and()
                .authorizeRequests()
                //接口匿名訪問
                .antMatchers("/doc.html",
                        "/favicon.ico",
                        "/v2/api-docs",
                        "/swagger-resources/**",
                        "/webjars/**","/user/login").anonymous()//攜帶token了就無法訪問了
                .anyRequest().authenticated();
        http.addFilterBefore(jwtTokenAdminInterceptor, UsernamePasswordAuthenticationFilter.class);
    }
    //暴露認證方法變?yōu)閎ean對象
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

關(guān)鍵在于以下代碼

                .antMatchers("/doc.html",
                        "/favicon.ico",
                        "/v2/api-docs",
                        "/swagger-resources/**",
                        "/webjars/**","/user/login").anonymous()

3.登錄接口實現(xiàn)

由于之前已經(jīng)實現(xiàn)了放行,我們只需要完成查詢數(shù)據(jù)庫,并且將數(shù)據(jù)生成jwt即可
在上面的配置中,我們已經(jīng)把認證方法暴露為bean對象,我們實現(xiàn)該方法即可

    //暴露認證方法變?yōu)閎ean對象
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

示例如下

package com.nie.sportserver.service.impl;
import com.nie.sportpojo.entity.LoginUser;
import com.nie.sportpojo.entity.User;
import com.nie.sportserver.mapper.LoginMapper;
import com.nie.sportserver.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Service
public class UserDetailServiceImpl implements UserDetailsService {
    @Autowired
    private LoginMapper loginMapper;
    @Autowired
    private UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //查詢用戶信息
        User user = loginMapper.getByUserName(username);
        //把數(shù)據(jù)封裝為UserDetail返回
        //todo 查詢對應(yīng)的權(quán)限信息
        List<String> list = new ArrayList<>(userMapper.selectPermsByUserId(user.getId()));
        LoginUser loginUser = new LoginUser(user,list);
        return loginUser;
    }
}

4.攔截器實現(xiàn)

在前面的配置中,我們已經(jīng)將普通請求攔截了,并且使用攔截器

    @Autowired
    JwtTokenAdminInterceptor jwtTokenAdminInterceptor;

這里來實現(xiàn)攔截器

package com.nie.sportserver.Interceptor;
import com.nie.sportcommon.utills.JwtUtil;
import com.nie.sportpojo.entity.LoginUser;
import com.nie.sportpojo.entity.User;
import com.nie.sportserver.mapper.LoginMapper;
import com.nie.sportserver.mapper.UserMapper;
import com.nie.sportserver.properties.JwtProperties;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
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.ArrayList;
import java.util.Arrays;
import java.util.List;
@Component
@Slf4j
public class JwtTokenAdminInterceptor extends OncePerRequestFilter {
    @Autowired
    private JwtProperties jwtProperties;
    @Autowired
    private LoginMapper loginMapper;
    @Autowired
    private UserMapper userMapper;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String requestURI = request.getRequestURI();
        //從請求頭中獲取令牌
        String token = request.getHeader(jwtProperties.getAdminTokenName());
        if (!StringUtils.hasText((token))) {
            filterChain.doFilter(request, response);
            return;
        }
        //校驗令牌
        Long userId;
        try {
            log.info("jwt校驗{}", token);
            //token解析
            Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
            userId = Long.valueOf(claims.get("userId").toString());
            log.info("當(dāng)前用戶id:{}", userId);
        } catch (Exception ex) {
            throw new RuntimeException("token非法");
        }
        User user = loginMapper.getByUserId(userId);
        List<String> list = new ArrayList<>(userMapper.selectPermsByUserId(user.getId()));
        LoginUser loginUser = new LoginUser(user,list);
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(loginUser,null,loginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        //放行
        filterChain.doFilter(request, response);
    }
}

其他工具類

jwt依賴

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

jwt工具類

package com.nie.sportcommon.utills;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;
public class JwtUtil {
    /**
     * 生成jwt
     * 使用Hs256算法, 私匙使用固定秘鑰
     *
     * @param secretKey jwt秘鑰
     * @param ttlMillis jwt過期時間(毫秒)
     * @param claims    設(shè)置的信息
     * @return
     */
    public static String createJWT(String secretKey, long ttlMillis, Map<String, Object> claims) {
        // 指定簽名的時候使用的簽名算法,也就是header那部分
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        // 生成JWT的時間
        long expMillis = System.currentTimeMillis() + ttlMillis;
        Date exp = new Date(expMillis);
        // 設(shè)置jwt的body
        JwtBuilder builder = Jwts.builder()
                // 如果有私有聲明,一定要先設(shè)置這個自己創(chuàng)建的私有的聲明,這個是給builder的claim賦值,一旦寫在標準的聲明賦值之后,就是覆蓋了那些標準的聲明的
                .setClaims(claims)
                // 設(shè)置簽名使用的簽名算法和簽名使用的秘鑰
                .signWith(signatureAlgorithm, secretKey.getBytes(StandardCharsets.UTF_8))
                // 設(shè)置過期時間
                .setExpiration(exp);
        return builder.compact();
    }
    /**
     * Token解密
     *
     * @param secretKey jwt秘鑰 此秘鑰一定要保留好在服務(wù)端, 不能暴露出去, 否則sign就可以被偽造, 如果對接多個客戶端建議改造成多個
     * @param token     加密后的token
     * @return
     */
    public static Claims parseJWT(String secretKey, String token) {
        // 得到DefaultJwtParser
        Claims claims = Jwts.parser()
                // 設(shè)置簽名的秘鑰
                .setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8))
                // 設(shè)置需要解析的jwt
                .parseClaimsJws(token).getBody();
        return claims;
    }
}

權(quán)限

權(quán)限認證使用 @PreAuthorize(“hasAuthority(‘’)”)注解

總結(jié)

本文對jwt登錄校驗,權(quán)限管理的原理簡單描述,并且提供了實現(xiàn)方案

到此這篇關(guān)于SpringSecurity+jwt實現(xiàn)登錄及權(quán)限認證功能的文章就介紹到這了,更多相關(guān)SpringSecurity jwt權(quán)限認證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java程序設(shè)計之12個經(jīng)典樣例

    Java程序設(shè)計之12個經(jīng)典樣例

    這篇文章主要給大家分享關(guān)于Java程序設(shè)計11個經(jīng)典樣例,主要以舉例的形式詳細的講解了Java程序設(shè)計的各種方法,需要的朋友可以參考一下文章具體的內(nèi)容
    2021-10-10
  • java中參數(shù)傳遞方式詳解

    java中參數(shù)傳遞方式詳解

    這篇文章主要介紹了java中參數(shù)傳遞方式詳解的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Java如何輸出windows中的全部漢字

    Java如何輸出windows中的全部漢字

    這篇文章主要介紹了Java如何輸出windows中的全部漢字問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • SpringBoot打包成Docker鏡像的幾種實現(xiàn)方式

    SpringBoot打包成Docker鏡像的幾種實現(xiàn)方式

    Spring Boot是一個用于構(gòu)建獨立的、可執(zhí)行的Spring應(yīng)用程序的框架,結(jié)合使用Spring Boot和Docker,可以方便地將應(yīng)用程序部署到不同的環(huán)境中本文,主要介紹了SpringBoot打包成Docker鏡像的幾種實現(xiàn)方式,感興趣的可以了解一下
    2024-01-01
  • Spring boot攔截器實現(xiàn)IP黑名單的完整步驟

    Spring boot攔截器實現(xiàn)IP黑名單的完整步驟

    這篇文章主要給大家介紹了關(guān)于Spring boot攔截器實現(xiàn)IP黑名單的完整步驟,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用Spring boot攔截器具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • IDEA搭建配置Java?Web項目的詳細步驟

    IDEA搭建配置Java?Web項目的詳細步驟

    這篇文章詳細介紹了如何使用IDEA創(chuàng)建和配置JavaWeb項目,包括項目結(jié)構(gòu)設(shè)置、WEB-INF目錄和jsp文件的創(chuàng)建,以及Tomcat的配置,是Java初學(xué)者的實用指南,需要的朋友可以參考下
    2024-10-10
  • MyBatis-Plus實現(xiàn)公共字段自動填充功能詳解

    MyBatis-Plus實現(xiàn)公共字段自動填充功能詳解

    在開發(fā)中經(jīng)常遇到多個實體類有共同的屬性字段,這些字段屬于公共字段,也就是很多表中都有這些字段,能不能對于這些公共字段在某個地方統(tǒng)一處理,來簡化開發(fā)呢?MyBatis-Plus就提供了這一功能,本文就來為大家詳細講講
    2022-08-08
  • 使用proguard對maven構(gòu)建的springboot項目進行混淆方式

    使用proguard對maven構(gòu)建的springboot項目進行混淆方式

    文章介紹了如何使用ProGuard對Maven構(gòu)建的Spring Boot項目進行混淆,并解決混淆后可能遇到的版本兼容性問題和類名沖突問題,主要步驟包括下載高版本的ProGuard、配置POM文件、添加ProGuard配置文件、修改Spring Boot啟動文件以避免類名沖突
    2024-11-11
  • Spring構(gòu)造器注入及@Autowired、lombok的@RequiredArgsConstructor的異同點說明

    Spring構(gòu)造器注入及@Autowired、lombok的@RequiredArgsConstructor的異同點說明

    本文介紹了Spring框架中構(gòu)造器注入的實現(xiàn)原理,包括Spring如何找到參數(shù)、構(gòu)造器注入與Autowired的區(qū)別,以及為什么Spring官方推薦構(gòu)造器注入,文章還強調(diào)了構(gòu)造器注入中使用final關(guān)鍵字的好處,并提供了代碼示例,幫助讀者更好地理解和應(yīng)用Spring的最佳實踐
    2026-03-03
  • Opencv實現(xiàn)身份證OCR識別的示例詳解

    Opencv實現(xiàn)身份證OCR識別的示例詳解

    這篇文章主要為大家詳細介紹了如何使用Opencv實現(xiàn)身份證OCR識別功能,文中的示例代碼講解詳細,具有一定的學(xué)習(xí)價值,感興趣的小伙伴可以跟隨小編一起了解一下
    2024-03-03

最新評論

巴彦淖尔市| 芷江| 浮山县| 德清县| 双城市| 秦安县| 普安县| 呈贡县| 老河口市| 乳源| 营口市| 夏河县| 夏河县| 通化县| 宜黄县| 淳化县| 全南县| 平遥县| 米易县| 田林县| 天柱县| 德阳市| 新野县| 鄂州市| 甘洛县| 新安县| 沾化县| 沅江市| 晴隆县| 长春市| 渝中区| 千阳县| 瓮安县| 赤城县| 全州县| 宝丰县| 冕宁县| 辽阳县| 扎囊县| 岐山县| 玛沁县|