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

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

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

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

Spring Security的主要功能包括

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

Spring Security是一個(gè)功能強(qiáng)大、靈活可擴(kuò)展的安全框架,可以幫助開發(fā)人員在Java應(yīng)用程序中實(shí)現(xiàn)全面的身份驗(yà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中可以對(duì)訪問(wèn)權(quán)限進(jìn)行設(shè)置,將登錄以及注冊(cè)接口設(shè)置為開放(不然系統(tǒng)就無(wú)法訪問(wèn)),也可以將不需要進(jìn)行權(quán)限認(rèn)證的接口也再此設(shè)置為開發(fā);同時(shí)也可以通過(guò)注解的方式對(duì)需要進(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()
                //不通過(guò)Session獲取SecurityContext
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()

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

                // 除上面外的所有請(qǐng)求全部需要鑒權(quán)認(rèn)證
                .anyRequest().authenticated();
        //添加過(guò)濾器
        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  一個(gè)小時(shí)
    //設(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è)置過(guò)期時(shí)間
        return builder.compact();
    }

    /**
     * 生成jtw
     * @param subject token中要存放的數(shù)據(jù)(json格式)
     * @param ttlMillis token超時(shí)時(shí)間
     * @return
     */
    public static String createJWT(String subject, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 設(shè)置過(guò)期時(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ā)時(shí)間
                .signWith(signatureAlgorithm, secretKey) //使用HS256對(duì)稱加密算法簽名, 第二個(gè)參數(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è)置過(guò)期時(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();
    }


}

定義用戶類

實(shí)現(xiàn)UserDetails接口,對(duì)用戶權(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();
    }

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

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

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

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

實(shí)現(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("用戶名或密碼錯(cuò)誤");
    }
    List<String> list = menuMapper.selectPermsByUserId(user.getId());

    return new LoginUser(user,list);
}

配置過(guò)濾器

@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)限不足的返回類

這兩個(gè)方法,在SecurityConfig中進(jìn)行添加。當(dāng)對(duì)于清空出現(xiàn)時(shí),調(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);
    }
}

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

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

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

    return addressService.getUserAddress(userId);
}

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

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

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

總結(jié)

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

相關(guān)文章

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

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

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

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

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

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

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

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

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

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

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

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

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

    JAVA對(duì)象clone方法代碼實(shí)例解析

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

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

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

    解決dubbo錯(cuò)誤ip及ip亂入問(wèn)題的方法

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

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

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

最新評(píng)論

民县| 怀集县| 东丽区| 德格县| 理塘县| 城固县| 鄂尔多斯市| 凤凰县| 安义县| 杨浦区| 新建县| 德惠市| 九台市| 黄大仙区| 彰化县| 萨迦县| 施秉县| 十堰市| 佳木斯市| 滦平县| 大连市| 徐水县| 郁南县| 英吉沙县| 宁明县| 济南市| 吴桥县| 庄河市| 崇州市| 垦利县| 安康市| 建水县| 东安县| 饶阳县| 普安县| 太谷县| 黎川县| 天津市| 和龙市| 崇礼县| 尚志市|