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

SpringBoot中SpringSecurity安全框架的基本配置與使用方式

 更新時間:2026年03月13日 15:30:17   作者:胡思亂想罷了~  
Spring Security是Spring框架的安全性解決方案,提供了身份驗證、授權(quán)、認(rèn)證流程安全控制等全面安全功能,廣泛應(yīng)用于Java應(yīng)用程序中

Spring Security是一個基于Spring框架的安全性解決方案,提供了全面的安全功能和集成能力,用于保護Java應(yīng)用程序的身份驗證、授權(quán)和其他安全需求。

Spring Security的主要功能包括

  • 身份驗證(Authentication):Spring Security提供了多種身份驗證機制。
  • 授權(quán)(Authorization):Spring Security支持基于角色和權(quán)限的授權(quán)機制,可以精確控制用戶對系統(tǒng)資源的訪問權(quán)限。它提供了注解和標(biāo)簽,使開發(fā)人員可以在代碼中靈活定義和配置授權(quán)規(guī)則。
  • 認(rèn)證流程的安全控制:Spring Security提供了很多機制來確保認(rèn)證流程的安全性。
  • Web安全:Spring Security可以通過過濾器鏈的方式保護Web應(yīng)用程序的安全性。
  • 方法級安全:Spring Security允許在方法級別上進(jìn)行安全控制,通過注解或XML配置來限制對特定方法的訪問權(quán)限。
  • 安全事件和審計:Spring Security提供了安全事件機制,可以記錄和處理安全相關(guān)的事件,例如登錄成功、權(quán)限拒絕等。它還支持審計功能,可用于記錄和追蹤用戶的操作行為。

Spring Security是一個功能強大、靈活可擴展的安全框架,可以幫助開發(fā)人員在Java應(yīng)用程序中實現(xiàn)全面的身份驗證和授權(quán)功能,提高應(yīng)用程序的安全性和可信度。

在SpringBoot中使用首先需要導(dǎo)入依賴

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

配置SecurityConfig和Jwt工具類

在SecurityConfig中可以對訪問權(quán)限進(jìn)行設(shè)置,將登錄以及注冊接口設(shè)置為開放(不然系統(tǒng)就無法訪問),也可以將不需要進(jìn)行權(quán)限認(rèn)證的接口也再此設(shè)置為開發(fā);同時也可以通過注解的方式對需要進(jìn)行權(quán)限認(rèn)證的接口進(jìn)行設(shè)置。

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return  new BCryptPasswordEncoder();
    }

    @Autowired
    private JwtAuthenticationTokenFilter filter;

    @Autowired
    private AuthenticationEntryPoint authenticationEntryPoint;

    @Resource
    private AccessDeniedHandler accessDeniedHandler;
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                //關(guān)閉csrf
                .csrf().disable()
                //不通過Session獲取SecurityContext
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()

                // 對于登錄接口 允許匿名訪問 未登錄狀態(tài)也可以訪問
                .antMatchers("/login/login").anonymous()
                .antMatchers("/login/register").anonymous()
                .antMatchers("/login/sendCode").anonymous()
                .antMatchers("/pay/notify").anonymous()
                // 需要用戶帶有管理員權(quán)限
//                .antMatchers("/find").hasRole("管理員")
//                // 需要用戶具備這個接口的權(quán)限
//                .antMatchers("/find").hasAuthority("menu:user")

                // 除上面外的所有請求全部需要鑒權(quán)認(rèn)證
                .anyRequest().authenticated();
        //添加過濾器
        http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class);

        //配置異常處理器
        http.exceptionHandling()
                //配置認(rèn)證失敗處理器
                .authenticationEntryPoint(authenticationEntryPoint)
                .accessDeniedHandler(accessDeniedHandler);

        //允許跨域
        http.cors();
    }

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

    //有效期為
    public static final Long JWT_TTL = 60 * 60 *1000L;// 60 * 60 *1000  一個小時
    //設(shè)置秘鑰明文
    public static final String JWT_KEY = "sangeng";

    public static String getUUID(){
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        return token;
    }

    /**
     * 生成jtw
     * @param subject token中要存放的數(shù)據(jù)(json格式)
     * @return
     */
    public static String createJWT(String subject) {
        JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 設(shè)置過期時間
        return builder.compact();
    }

    /**
     * 生成jtw
     * @param subject token中要存放的數(shù)據(jù)(json格式)
     * @param ttlMillis token超時時間
     * @return
     */
    public static String createJWT(String subject, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 設(shè)置過期時間
        return builder.compact();
    }

    private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        SecretKey secretKey = generalKey();
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        if(ttlMillis==null){
            ttlMillis=JwtUtil.JWT_TTL;
        }
        long expMillis = nowMillis + ttlMillis;
        Date expDate = new Date(expMillis);
        return Jwts.builder()
                .setId(uuid)              //唯一的ID
                .setSubject(subject)   // 主題  可以是JSON數(shù)據(jù)
                .setIssuer("sg")     // 簽發(fā)者
                .setIssuedAt(now)      // 簽發(fā)時間
                .signWith(signatureAlgorithm, secretKey) //使用HS256對稱加密算法簽名, 第二個參數(shù)為秘鑰
                .setExpiration(expDate);
    }

    /**
     * 創(chuàng)建token
     * @param id
     * @param subject
     * @param ttlMillis
     * @return
     */
    public static String createJWT(String id, String subject, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 設(shè)置過期時間
        return builder.compact();
    }

    public static void main(String[] args) throws Exception {
        String jwt = createJWT("1234");
        Claims claims = parseJWT(jwt);
        String subject = claims.getSubject();

        System.out.println(subject);
    }

    /**
     * 生成加密后的秘鑰 secretKey
     * @return
     */
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }

    /**
     * 解析
     *
     * @param jwt
     * @return
     * @throws Exception
     */
    public static Claims parseJWT(String jwt) throws Exception {
        SecretKey secretKey = generalKey();
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt)
                .getBody();
    }


}

定義用戶類

實現(xiàn)UserDetails接口,對用戶權(quán)限進(jìn)行封裝。

@Data
@NoArgsConstructor
public class LoginUser implements UserDetails {

    private User user;

    private List<String> permissions;

    public LoginUser(User user, List<String> permissions) {
        this.user = user;
        this.permissions = permissions;
    }


    //返回權(quán)限信息

    @JSONField(serialize = false)  //不需要存到redis中,進(jìn)行序列化忽略
    private List<SimpleGrantedAuthority> authorities;
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {

        if (authorities != null){
            return authorities;
        }
       authorities = permissions.stream()
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());

        return authorities;
    }

    @Override
    public String getPassword() {
        return user.getUserPwd();
    }

    @Override
    public String getUsername() {
        return user.getUserName();
    }

    //判斷是否沒過期
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

實現(xiàn)UserDetailsService接口

重寫loadUserByUsername方法查詢用戶權(quán)限信息

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

    //查詢用戶信息
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(User::getUserName, username);
    User user = userMapper.selectOne(wrapper);
    //如果沒有查詢到用戶就拋出異常
    if (Objects.isNull(user)){
        throw new RuntimeException("用戶名或密碼錯誤");
    }
    List<String> list = menuMapper.selectPermsByUserId(user.getId());

    return new LoginUser(user,list);
}

配置過濾器

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Autowired
    private RedisCache redisCache;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = request.getHeader("token");

        if (!StringUtils.hasText(token)) {
            //token為空,放行
            filterChain.doFilter(request, response);
            return;
        }
        //解析token
        String userId;
        try {
            Claims claims = JwtUtil.parseJWT(token);
            userId = claims.getSubject();
        } catch (Exception e) {
            throw new RuntimeException("token非法");
        }
        //從redis中獲取用戶信息
        String redisKey = "login:" + userId;

        LoginUser loginUser = redisCache.getCacheObject(redisKey);
        if (Objects.isNull(loginUser)){
            throw new RuntimeException("用戶未登錄");
        }
        //存入securityContextHolder
        // 獲取權(quán)限信息封裝到Authentication中
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());

        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        //放行
        filterChain.doFilter(request, response);
    }
}

配置認(rèn)證失敗和權(quán)限不足的返回類

這兩個方法,在SecurityConfig中進(jìn)行添加。當(dāng)對于清空出現(xiàn)時,調(diào)用方法,返回給前端狀態(tài)碼,以及自定義信息。

@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        Result result = new Result(HttpStatus.UNAUTHORIZED.value(), "認(rèn)證失敗");
        String json = JSON.toJSONString(result);
        //處理異常
        WebUtils.renderString(response, json);

    }
}
@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        Result result = new Result(HttpStatus.FORBIDDEN.value(), "權(quán)限不足");
        String json = JSON.toJSONString(result);
        WebUtils.renderString(response, json);
    }
}

配置完成后,在前端頁面訪問后端接口,過濾器會進(jìn)行攔截,判斷前端請求中請求頭是否攜帶token,攜帶并成功驗證用戶后,會將用戶的權(quán)限信息封裝到Authentication中,后續(xù)判斷該用戶是否擁有訪問該接口的權(quán)限。

例如設(shè)置下面接口的訪問中需要用戶擁有g(shù)etUserAddress權(quán)限。

@RequestMapping("/getUserAddress")
@PreAuthorize("hasAuthority('getUserAddress')")
public Result getUserAddress(Long userId) {

    return addressService.getUserAddress(userId);
}

用戶、角色、權(quán)限表信息如下

可以看到用戶1不存在訪問getUserAddress的權(quán)限。

當(dāng)使用用戶1登錄后,在前端對該接口進(jìn)行訪問時,后端會返回權(quán)限不足的狀態(tài)碼以及相應(yīng)的信息信息。該接口的方法也不會執(zhí)行。

總結(jié)

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

相關(guān)文章

  • mybatis plus開發(fā)過程中遇到的問題記錄及解決

    mybatis plus開發(fā)過程中遇到的問題記錄及解決

    這篇文章主要介紹了mybatis plus開發(fā)過程中遇到的問題記錄及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Maven 生成打包可執(zhí)行jar包的方法步驟

    Maven 生成打包可執(zhí)行jar包的方法步驟

    這篇文章主要介紹了Maven 生成打包可執(zhí)行jar包的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Java集合快速失敗與安全失敗解析

    Java集合快速失敗與安全失敗解析

    這篇文章主要介紹了Java集合快速失敗與安全失敗解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java中import導(dǎo)入的用法說明

    Java中import導(dǎo)入的用法說明

    這篇文章主要介紹了Java中import導(dǎo)入的用法說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • java 域?qū)ο蠊蚕頂?shù)據(jù)的實現(xiàn)

    java 域?qū)ο蠊蚕頂?shù)據(jù)的實現(xiàn)

    本文主要介紹了java 域?qū)ο蠊蚕頂?shù)據(jù)的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • Java 隨機生成驗證碼(支持大小寫字母、數(shù)字、隨機字體)的實例

    Java 隨機生成驗證碼(支持大小寫字母、數(shù)字、隨機字體)的實例

    java隨機產(chǎn)生驗證碼,可以隨機生成數(shù)字、大寫字母、小寫字母。還可以隨機生成文字字體、及大小。在圖片上面可能字體都不不同、大小不等
    2013-05-05
  • JAVA對象clone方法代碼實例解析

    JAVA對象clone方法代碼實例解析

    這篇文章主要介紹了JAVA對象clone方法代碼實例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-03-03
  • spring boot 統(tǒng)一JSON格式的接口返回結(jié)果的實現(xiàn)

    spring boot 統(tǒng)一JSON格式的接口返回結(jié)果的實現(xiàn)

    這篇文章主要介紹了spring boot 統(tǒng)一JSON格式的接口返回結(jié)果的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • 解決dubbo錯誤ip及ip亂入問題的方法

    解決dubbo錯誤ip及ip亂入問題的方法

    今天小編就為大家分享一篇關(guān)于解決dubbo錯誤ip及ip亂入問題的方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • Java異常處理 如何跟蹤異常的傳播路徑

    Java異常處理 如何跟蹤異常的傳播路徑

    這篇文章主要介紹了Java異常處理 如何跟蹤異常的傳播路徑,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-07-07

最新評論

平昌县| 东乡县| 沙雅县| 丁青县| 东平县| 黔东| 贺州市| 寿阳县| 政和县| 富顺县| 云浮市| 榆树市| 沂源县| 木兰县| 本溪市| 涿鹿县| 焉耆| 荔浦县| 张家川| 龙游县| 涞源县| 子洲县| 岫岩| 宁河县| 韩城市| 泗水县| 山东省| 柏乡县| 泽普县| 岳阳市| 漠河县| 乌恰县| 财经| 朔州市| 万盛区| 津南区| 泰和县| 永平县| 惠州市| 延吉市| 叙永县|