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

SpringBoot?Security從入門到實(shí)戰(zhàn)示例教程

 更新時(shí)間:2022年05月06日 09:52:32   作者:lakernote  
Spring?Security是一個(gè)功能強(qiáng)大且高度可定制的身份驗(yàn)證和訪問控制框架,接下來通過本文給大家介紹SpringBoot?Security從入門到實(shí)戰(zhàn)示例教程,感興趣的朋友一起看看吧

前言

Spring Security是一個(gè)功能強(qiáng)大且高度可定制的身份驗(yàn)證和訪問控制框架。提供了完善的認(rèn)證機(jī)制和方法級的授權(quán)功能。是一款非常優(yōu)秀的權(quán)限管理框架。它的核心是一組過濾器鏈,不同的功能經(jīng)由不同的過濾器。這篇文章給大家講解SpringBoot Security從入門到實(shí)戰(zhàn),內(nèi)容如下所示:

入門

測試接口

假設(shè)我們用下面的接口做權(quán)限測試。

@RestController
public class LakerController {
    @GetMapping("/laker")
    public String laker() {
        return IdUtil.simpleUUID();
    }
    @GetMapping("/laker/q")
    public String lakerQ() {
        return IdUtil.simpleUUID();
    }
}

瀏覽器訪問:http://localhost:8080/laker,結(jié)果如下:

增加依賴

pom.xml,添加 spring-boot-starter-securtiy 依賴。

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

再次訪問http://localhost:8080/laker,結(jié)果如下:

簡要解析

我們訪問http://localhost:8080/laker,security判斷我們沒有登錄,則會302重定向http://localhost:8080/login(默認(rèn))

  • security會返回一個(gè)默認(rèn)的登錄頁。
  • 默認(rèn)用戶名為:user,密碼在服務(wù)啟動時(shí),會隨機(jī)生成一個(gè),可以查看啟動日志如下:

2022-05-02 21:01:03.697  INFO 17896 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2022-05-02 21:01:03.825  INFO 17896 --- [           main] .s.s.UserDetailsServiceAutoConfiguration : 

Using generated security password: e53fef6a-3f61-43c3-9609-ce88fd7c0841

當(dāng)然,可以通過配置文件設(shè)置默認(rèn)的用戶名、密碼、角色。

spring:
  security:
    user:
      # 默認(rèn)是 user
      name: laker
      password: laker
      roles:
        - ADMIN
        - TESTER

以上的默認(rèn)都是可以修改的哈。

判斷是否登錄使用傳統(tǒng)的cookie session模式哈,JSESSIONID E3512CD1A81DB7F2144C577BA38D2D92 HttpOnly true

自定義配置

實(shí)際項(xiàng)目中我們的用戶、密碼、角色、權(quán)限、資源都是存儲在數(shù)據(jù)庫中的,我們可以通過自定義類繼承 WebSecurityConfigurerAdapter,從而實(shí)現(xiàn)對 Spring Security 更多的自定義配置。

@Configuration
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {
		...
}

配置密碼加密方式

必須配置,否則報(bào)空指針異常。

   @Bean
    PasswordEncoder passwordEncoder() {
        // 不加密
        return NoOpPasswordEncoder.getInstance();
    }

Spring Security 提供了多種密碼加密方案,官方推薦使用 BCryptPasswordEncoder

BCryptPasswordEncoder 使用 BCrypt 強(qiáng)哈希函數(shù),開發(fā)者在使用時(shí)可以選擇提供 strengthSecureRandom 實(shí)例。strength 取值在 4~31 之間(默認(rèn)為 10)。strength 越大,密鑰的迭代次數(shù)越多(密鑰迭代次數(shù)為 2^strength)。如果是數(shù)據(jù)庫認(rèn)證,庫里的密碼同樣也存放加密后的密碼。同一密碼每次 Bcrypt 生成的結(jié)果都會變化不會重復(fù)。

配置AuthenticationManagerBuilder 認(rèn)證用戶、角色權(quán)限

支持直接配置內(nèi)存認(rèn)證模式和配置UserDetailsServiceBean方式

內(nèi)存認(rèn)證模式,實(shí)際項(xiàng)目不用這個(gè)哦。(僅做了解)

 /**
     * 配置用戶及其對應(yīng)的角色
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin").password("123").roles("ADMIN", "USER")
                .and()
                .withUser("laker").password("123").roles("USER");
    }

上面在UserDetailsService的實(shí)現(xiàn)之一InMemoryUserDetailsManager中,即存儲在內(nèi)存中。

自定義UserDetailsServiceBean方式,實(shí)際項(xiàng)目都是使用這個(gè),可定制化程度高。

步驟一:定義一個(gè)LakerUserService實(shí)現(xiàn)UserDetailsService,配置成SpringBean。該方法將在用戶登錄時(shí)自動調(diào)用。

@Service
public class LakerUserService implements UserDetailsService {
    @Autowired
    UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // username 就是前端傳遞的例如 laker 123,即 laker
        User user = userMapper.loadUserByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("賬戶不存在!");
        }
        user.setAuthorities(...);
        return user;
    }
}

username

password(加密后的密碼)

authorities

返回的Bean中以上3個(gè)都不能為空。返回User后由系統(tǒng)提供的 DaoAuthenticationProvider 類去比對密碼是否正確。

Spring Security默認(rèn)支持表單請求登錄的源碼,UsernamePasswordAuthenticationFilter.java

步驟二:在把自定義的LakerUserService裝載進(jìn)去.

@Autowired
UserService userService;
...
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userService);
}

步驟三:其中我們的業(yè)務(wù)用戶User必須要實(shí)現(xiàn)UserDetails接口,并實(shí)現(xiàn)該接口中的 7 個(gè)方法:

  • getAuthorities():獲取當(dāng)前用戶對象所具有的權(quán)限信息
  • getPassword():獲取當(dāng)前用戶對象的密碼

返回的密碼和用戶輸入的登錄密碼不匹配,會自動拋出 BadCredentialsException 異常。

  • getUsername():獲取當(dāng)前用戶對象的用戶名
  • isAccountNonExpired():當(dāng)前賬戶是否未過期
  • isAccountNonLocked():當(dāng)前賬戶是否未鎖定
  • 返回了 false,會自動拋出 AccountExpiredException 異常。
  • isCredentialsNonExpired():當(dāng)前賬戶密碼是否未過期
  • isEnabled():當(dāng)前賬戶是否可用
@Data
public class User implements UserDetails {
    private Integer id;
    private String username;
    private String password;
    private Boolean enabled;
    private Boolean locked;
    private List<String> authorities;
    @Override
    public String getPassword() {
        return password;
    }
    @Override
    public String getUsername() {
        return username;
    }
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    @Override
    public boolean isAccountNonLocked() {
        return !locked;
    }
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
    @Override
    public boolean isEnabled() {
        return enabled;
    }
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<SimpleGrantedAuthority> authoritiesList = new ArrayList<>();
        for (String authority : authorities) {
            authoritiesList.add(new SimpleGrantedAuthority(authority));
        }
        return authoritiesList;
    }
}

配置HttpSecurity Url訪問權(quán)限

  /**
     * 配置 URL 訪問權(quán)限
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //
        http    // 1.開啟 HttpSecurity 配置
                .authorizeRequests()
                // laker/** 模式URL必須具備laker.query
                .antMatchers("/laker/**").hasAnyAuthority("laker.query")
                // 用戶訪問其它URL都必須認(rèn)證后訪問(登錄后訪問)
                .anyRequest().authenticated()
                .and()
                // 2.開啟表單登錄,前后端分離的時(shí)候不用這個(gè)
                .formLogin()
                // 未登錄時(shí) 重定向的url 默認(rèn)是/login 內(nèi)置的頁面,可以自己自定義哈。一般前后端分離,不用這個(gè)
//                .loginPage("/login")
                //
//                .defaultSuccessUrl("/user",true)
//                .usernameParameter("username") // default is username
//                .passwordParameter("password") // default is password
//                .loginPage("/authentication/login") // default is /login with an HTTP get
//                .failureUrl("/authentication/login?failed") // default is /login?error
//                .loginProcessingUrl("/authentication/login/process") // default is /login
                .and()
                // 3.關(guān)閉csrf,前后端分離不需要這個(gè)。
                .csrf().disable();
                //授權(quán)碼模式需要 會彈出默認(rèn)自帶的登錄框
                http.httpBasic();   
        		// 開啟注銷登錄的配置 
                http.logout()
                    // 配置注銷登錄請求URL為"/logout"(默認(rèn)也就是 /logout)
                    .logoutSuccessUrl("/logout")
                    .clearAuthentication(true) // 清除身份認(rèn)證信息
                    .invalidateHttpSession(true) // 使 session 失效;
    }
  • formLogin() 表示開啟表單登錄
  • **defaultSuccessUrl()**表示默認(rèn)登錄驗(yàn)證成功跳轉(zhuǎn)的url,默認(rèn)重定向到上次訪問未成功的,如果沒有則重定向到/.
  • loginProcessingUrl() 方法配置登錄接口為“/login”,即可以直接調(diào)用“/login”接口,發(fā)起一個(gè) POST 請求進(jìn)行登錄,登錄參數(shù)中用戶名必須為 username,密碼必須為 password,配置 loginProcessingUrl 接口主要是方便 Ajax 或者移動端調(diào)用登錄接口。

    anyRequest          |   匹配所有請求路徑
    access              |   SpringEl表達(dá)式結(jié)果為true時(shí)可以訪問
    anonymous           |   匿名可以訪問 所有人都能訪問,但是帶上 token訪問后會報(bào)錯403
    denyAll             |   用戶不能訪問 所有人都能訪問,包括帶上 token 訪問
    fullyAuthenticated  |   用戶完全認(rèn)證可以訪問(非remember-me下自動登錄)
    hasAnyAuthority     |   如果有參數(shù),參數(shù)表示權(quán)限,則其中任何一個(gè)權(quán)限可以訪問
    hasAnyRole          |   如果有參數(shù),參數(shù)表示角色,則其中任何一個(gè)角色可以訪問
    hasAuthority        |   如果有參數(shù),參數(shù)表示權(quán)限,則其權(quán)限可以訪問
    hasIpAddress        |   如果有參數(shù),參數(shù)表示IP地址,如果用戶IP和參數(shù)匹配,則可以訪問
    hasRole             |   如果有參數(shù),參數(shù)表示角色,則其角色可以訪問
    permitAll           |   用戶可以任意訪問
    rememberMe          |   允許通過remember-me登錄的用戶訪問
    authenticated       |   用戶登錄后可訪問

自定義successHandler

登錄成功后默認(rèn)是重定向url,我們可以自定義返回json用于前后端分離場景以及其他邏輯,例如成功之后發(fā)短信等。

http.formLogin().successHandler((req, resp, authentication) -> {
    // 發(fā)短信哈
    Object principal = authentication.getPrincipal();
    resp.setContentType("application/json;charset=utf-8");
    PrintWriter out = resp.getWriter();
    out.write(new ObjectMapper().writeValueAsString(principal));
    out.flush();
    out.close();
})

自定義failureHandler

登錄失敗回調(diào)

http.formLogin().failureHandler((req, resp, e) -> {
    resp.setContentType("application/json;charset=utf-8");
    PrintWriter out = resp.getWriter();
    out.write(e.getMessage());
    out.flush();
    out.close();
})

自定義未認(rèn)證處理

http.exceptionHandling()
.authenticationEntryPoint((req, resp, authException) -> {
            resp.setContentType("application/json;charset=utf-8");
            PrintWriter out = resp.getWriter();
            out.write("尚未登錄,請先登錄");
            out.flush();
            out.close();
        }
);

自定義權(quán)限不足處理

http.exceptionHandling()
				//沒有權(quán)限,返回json
				.accessDeniedHandler((request,response,ex) -> {
					response.setContentType("application/json;charset=utf-8");
					response.setStatus(HttpServletResponse.SC_FORBIDDEN);
					PrintWriter out = response.getWriter();
					Map<String,Object> map = new HashMap<String,Object>();
					map.put("code",403);
					map.put("message", "權(quán)限不足");
					out.write(objectMapper.writeValueAsString(map));
					out.flush();
					out.close();
				})

自定義注銷登錄

.logout()
.logoutUrl("/logout")
.logoutSuccessHandler((req, resp, authentication) -> {
    resp.setContentType("application/json;charset=utf-8");
    PrintWriter out = resp.getWriter();
    out.write("注銷成功");
    out.flush();
    out.close();
})

前后端分離場景

上面的都是入門的,實(shí)際項(xiàng)目中一般都是前后端分離的,在登錄時(shí)都是自定義登錄接口,例如登錄接口是restful風(fēng)格,增加了其他的驗(yàn)證碼參數(shù),還使用jwt來完成登錄鑒權(quán)等。

提供登錄接口

該接口需要在配置當(dāng)中放行,未授權(quán)訪問需要授權(quán)的請求時(shí),會返回401或者403狀態(tài)碼,前端可以根據(jù)這個(gè)進(jìn)行路由提示處理。

@RestController
public class LoginController {
   @Autowired
   LoginService ...
   @PostMapping("/login")
   public  login(@RequestBody Login login){
       ...
       return token;
   }
}

Service層創(chuàng)建UsernamePasswordAuthenticationToken對象,把用戶名和密碼封裝成Authentication對象.

@Service
public class LoginServiceImpl implements LoginService {
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserDetailsService userDetailsService;
    @Override
    public  doLogin(Login login) {
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password;
        Authentication  authenticate
        try {         // 該方法會去調(diào)用UserDetailsServiceImpl.loadUserByUsername
             authenticate = authenticationManager.authenticate(authenticationToken);
        } catch (AuthenticationException e) {
            e.printStackTrace();
        }
 
        if (Objects.isNull(authenticate)) {
            //用戶名密碼錯誤
            throw new ServicesException(...);
        }
        User authUser = (User) authenticate.getPrincipal();
        String token = JwtUtil.createJWT(username);
        Map<String, String> map = new HashMap<>();
        map.put("token", token);
        return map;
    }
}

自定義認(rèn)證過濾器

坊間有2種實(shí)現(xiàn)方式。

方式一:繼承UsernamePasswordAuthenticationFilter的寫法需要使用登陸成功處理器、失敗處理器等,還是需要按照security這一套來玩。

Spring Security默認(rèn)支持表單請求登錄的源碼UsernamePasswordAuthenticationFilter.java

方式二:使用Filter的寫法沒有任何限制怎么玩都行,比如說添加其他參數(shù)驗(yàn)證碼,返回json,token鑒權(quán)等。

@Component
public class LakerOncePerRequestFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws ServletException, IOException {
        String token = request.getHeader("Authorization");
        if (!StringUtils.isEmpty(token) )
        {
            // 校驗(yàn)token ...
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user, null, authorities;
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));                                     SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        chain.doFilter(request, response);
    }
}                                                                                                           //3、在UsernamePasswordAuthenticationFilter前添加認(rèn)證過濾器
http.addFilterBefore(lakerOncePerRequestFilter, UsernamePasswordAuthenticationFilter.class);

鑒權(quán)

1.注解鑒權(quán)

  • SpringSecurity配置類中開啟方法級的認(rèn)證
  • 使用 @PreAuthorize注解在方法或者類
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {
...
@RestController
public class Controller {
    @GetMapping("/hello")
    @PreAuthorize("hasAnyAuthority('laker.query')")
    public String test() {
}

2.自定義Bean動態(tài)鑒權(quán)

因?yàn)?code>@PreAuthorize支持SpringEL表達(dá)式,所以可以支持自定義SpringBean動態(tài)鑒權(quán)。

  • 先自定義一個(gè)SpringBean。
  • 使用 @PreAuthorize注解在方法或者類配合@PreAuthorize(“@rbacService.hasPermission(‘xx’)”)
@Component("rbacService")
public class LakerRBACService {
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        Object principal = authentication.getPrincipal();
        if (principal instanceof UserDetails) {
            UserDetails userDetails=(UserDetails)principal;

            /**
             * 該方法主要對比認(rèn)證過的用戶是否具有請求URL的權(quán)限,有則返回true
             */
            //本次要訪問的資源
              SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(request.getMethod() + "" + request.getRequestURI());

            //用戶擁有的權(quán)限中是否包含請求的url
            return userDetails.getAuthorities().contains(simpleGrantedAuthority);
        }
        return false;
    }
        public boolean hasPermission() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Object principal = authentication.getPrincipal();
        if (principal instanceof UserDetails) {
            UserDetails userDetails = (UserDetails) principal;
            /**
             * 該方法主要對比認(rèn)證過的用戶是否具有請求URL的權(quán)限,有則返回true
             */
            //本次要訪問的資源
            HttpServletRequest request =((ServletRequestAttributes)
                    RequestContextHolder.getRequestAttributes()).getRequest();

            SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(request.getRequestURI());
            //用戶擁有的權(quán)限中是否包含請求的url
            return userDetails.getAuthorities().contains(simpleGrantedAuthority);
        }
        return false;
    }
}
// controller方法
@PreAuthorize("@rbacService.hasPermission()")
public String test() {
}
// 或者高級的全局url鑒權(quán)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
         ...
      http.authorizeRequests() //設(shè)置授權(quán)請求,任何請求都要經(jīng)過下面的權(quán)限表達(dá)式處理
          .anyRequest().access("@rbacService.hasPermission(request,authentication)") //權(quán)限表達(dá)式     

3.擴(kuò)展默認(rèn)方法自定義擴(kuò)展根對象SecurityExpressionRoot

http://m.fzitv.net/article/245172.htm

1.創(chuàng)建自定義根對象

public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
    public CustomMethodSecurityExpressionRoot(Authentication authentication) {
        super(authentication);
    }
    /**
     * 自定義表達(dá)式
     * @param username 具有權(quán)限的用戶賬號
     */
    public boolean hasUser(String... username) {
        String name = this.getAuthentication().getName();
        HttpServletRequest request = ((ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes()).getRequest();
        String[] names = username;
        for (String nameStr : names) {
            if (name.equals(nameStr)) {
                return true;
            }
        }
        return false;
    }
}

2.創(chuàng)建自定義處理器

創(chuàng)建自定義處理器,主要是重寫創(chuàng)建根對象的方法。

public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
    @Override
    protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
        CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
        root.setThis(invocation.getThis());
        root.setPermissionEvaluator(getPermissionEvaluator());
        root.setTrustResolver(getTrustResolver());
        root.setRoleHierarchy(getRoleHierarchy());
        root.setDefaultRolePrefix(getDefaultRolePrefix());
        return root;
    }
}

3.配置GlobalMethodSecurityConfiguration
之前我們使用@EnableGlobalMethodSecurity開啟全局方法安全,而這些全局方法級別的安全配置就在GlobalMethodSecurityConfiguration配置類中。

可以擴(kuò)展這個(gè)類來自定義默認(rèn)值,但必須確保在類上指定@EnableGlobalMethodSecurity 注解,否則會bean沖突報(bào)錯。

@Configuration
// 將EnableGlobalMethodSecurity注解移到這里
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        return new CustomMethodSecurityExpressionHandler();
    }
}

4.controller使用自定義方法

@PreAuthorize("hasUser('laker','admin')")
public String test() {
    ...
}

登出

http.logout().logoutUrl("/logout").logoutSuccessHandler((request, response, authentication) -> {
            // 刪除用戶token
    		...
            // 返回json
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(HttpServletResponse.SC_OK);
            PrintWriter out = response.getWriter();
            out.write("OK");
            out.flush();
            out.close();
        });

跨域

@Override
protected void configure(HttpSecurity http) throws Exception {
	http.cors();//允許跨域,配置后SpringSecurity會自動尋找name=corsConfigurationSource的Bean
	http.csrf().disable();//關(guān)閉CSRF防御
}

@Configuration
public class CrosConfig {
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration cores=new CorsConfiguration();
        cores.setAllowCredentials(true);//允許客戶端攜帶認(rèn)證信息
        //springBoot 2.4.1版本之后,不可以用 * 號設(shè)置允許的Origin,如果不降低版本,則在跨域設(shè)置時(shí)使用setAllowedOriginPatterns方法
       // cores.setAllowedOrigins(Collections.singletonList("*"));//允許所有域名可以跨域訪問
        cores.setAllowedOriginPatterns(Collections.singletonList("*"));
        cores.setAllowedMethods(Arrays.asList("GET","POST","DELETE","PUT","UPDATE"));//允許哪些請求方式可以訪問
        cores.setAllowedHeaders(Collections.singletonList("*"));//允許服務(wù)端訪問的客戶端請求頭
        // 暴露哪些頭部信息(因?yàn)榭缬蛟L問默認(rèn)不能獲取全部頭部信息)
        cores.addExposedHeader(jsonWebTokenUtil.getHeader());
        // 注冊跨域配置
        // 也可以使用CorsConfiguration 類的 applyPermitDefaultValues()方法使用默認(rèn)配置
        source.registerCorsConfiguration("/**",cores.applyPermitDefaultValues());
        return source;
    }
}

全局配置

@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
    UserService userService;

    @Autowired
    TokenFilter tokenFilter;

    /**
     * 配置 URL 訪問權(quán)限
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //
        http    // 1.過濾請求
                .authorizeRequests()
                // 2.對于登錄login 驗(yàn)證碼captcha 允許訪問
                .antMatchers("/login").permitAll()
                // 用戶訪問其它URL都必須認(rèn)證后訪問(登錄后訪問)
                .anyRequest().authenticated()
                .and()
                // 3.關(guān)閉csrf
                .csrf().disable()
                // 4.基于token,所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                // 5.頁面能不能以 frame、 iframe、 object 形式嵌套在其他站點(diǎn)中,用來避免點(diǎn)擊劫持(clickjacking)攻擊
                .and().headers().frameOptions().disable();
        // 異常處理
        http.exceptionHandling()
                // 未認(rèn)證返回401
                .authenticationEntryPoint((req, response, authException) -> {
                    response.setContentType("application/json;charset=utf-8");
                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                    PrintWriter out = response.getWriter();
                    out.write("尚未登錄,請先登錄");
                    out.flush();
                    out.close();
                })
                // 沒有權(quán)限,返回403 json
                .accessDeniedHandler((request, response, ex) -> {
                    response.setContentType("application/json;charset=utf-8");
                    response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                    PrintWriter out = response.getWriter();
                    Map<String, Object> map = new HashMap<String, Object>();
                    map.put("code", 403);
                    map.put("message", "權(quán)限不足");
                    out.write(JSONUtil.toJsonPrettyStr(map));
                    out.flush();
                    out.close();
                });
        // 配置登出
        http.logout().logoutUrl("/logout").logoutSuccessHandler((request, response, authentication) -> {
                // 刪除用戶token
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(HttpServletResponse.SC_OK);
            PrintWriter out = response.getWriter();
            out.write("OK");
            out.flush();
            out.close();
        });
        // 添加JWT filter
        http.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class);
    }

    /**
     * 配置用戶及其對應(yīng)的角色
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService);
    }
    /**
     * 適用于靜態(tài)資源的防攔截,css、js、image 等文件
     * 配置的url不會保護(hù)它們免受CSRF、XSS、Clickjacking等的影響。
     * 相反,如果您想保護(hù)端點(diǎn)免受常見漏洞的侵害,請參閱configure(HttpSecurity)
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**", "/js/**");
    }
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    /**
     * 解決 無法直接注入 AuthenticationManager
     *
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception
    {
        return super.authenticationManagerBean();
    }
}

參考:

https://blog.csdn.net/X_lsod/article/details/122914659

https://blog.csdn.net/godleaf/article/details/108318403

https://blog.csdn.net/qq_43437874/article/details/119543579

到此這篇關(guān)于SpringBoot Security從入門到實(shí)戰(zhàn)示例教程的文章就介紹到這了,更多相關(guān)SpringBoot Security入門內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot框架搭建教程分享

    SpringBoot框架搭建教程分享

    這篇文章主要為大家詳細(xì)介紹了SpringBoot框架搭建教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • 如何利用Stream改變list中特定對象的某一屬性

    如何利用Stream改變list中特定對象的某一屬性

    這篇文章主要介紹了如何利用Stream改變list中特定對象的某一屬性問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • mybatis-plus復(fù)合主鍵的使用

    mybatis-plus復(fù)合主鍵的使用

    本文主要介紹了mybatis-plus復(fù)合主鍵的使用,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • 淺談MyBatis-plus入門使用

    淺談MyBatis-plus入門使用

    這幾天本人了解到了MyBatis-plus,一個(gè) Mybatis 增強(qiáng)工具包.經(jīng)過一番研究,發(fā)現(xiàn)這玩意真的好用,不用寫任何 xml ,內(nèi)置通用的 Mapper,而且完全是面向?qū)ο缶幊?文檔給的示例代碼,跟之前用過的 sequelize (Node.js 的 ORM)非常像,因此本人也嘗試了一把, 需要的朋友可以參考下
    2021-05-05
  • Java中Spring MVC接收表單數(shù)據(jù)的常用方法

    Java中Spring MVC接收表單數(shù)據(jù)的常用方法

    Spring MVC是Spring框架中的一個(gè)模塊,用于開發(fā)基于MVC(Model-View-Controller)架構(gòu)的Web應(yīng)用程序,它提供了一種輕量級的、靈活的方式來構(gòu)建Web應(yīng)用,同時(shí)提供了豐富的功能和特性,本文給大家介紹了Spring MVC接收表單數(shù)據(jù)的方法,需要的朋友可以參考下
    2024-05-05
  • SpringBoot+VUE實(shí)現(xiàn)前后端分離的實(shí)戰(zhàn)記錄

    SpringBoot+VUE實(shí)現(xiàn)前后端分離的實(shí)戰(zhàn)記錄

    這篇文章主要介紹了SpringBoot+VUE實(shí)現(xiàn)前后端分離的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Java設(shè)計(jì)模式之備忘錄模式使用詳解

    Java設(shè)計(jì)模式之備忘錄模式使用詳解

    這篇文章主要介紹了Java設(shè)計(jì)模式中備忘錄模式的使用,備忘錄設(shè)計(jì)模式也叫作快照模式,主要用于實(shí)現(xiàn)防丟失、撤銷、恢復(fù)等功能,本文將通過示例為大家講解備忘錄模式的定義與使用,需要的同學(xué)可以參考一下
    2024-02-02
  • Java泛型類與泛型方法的定義詳解

    Java泛型類與泛型方法的定義詳解

    這篇文章主要介紹了Java泛型類與泛型方法的定義,結(jié)合實(shí)例形式詳細(xì)分析了java泛型類與泛型方法定義、用法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下
    2019-08-08
  • java request.getHeader(

    java request.getHeader("user-agent")獲取瀏覽器信息的方法

    這篇文章主要介紹了java request.getHeader("user-agent")獲取瀏覽器信息的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • kotlin java 混合代碼 maven 打包實(shí)現(xiàn)

    kotlin java 混合代碼 maven 打包實(shí)現(xiàn)

    這篇文章主要介紹了kotlin java 混合代碼 maven 打包實(shí)現(xiàn),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03

最新評論

荃湾区| 连州市| 巨野县| 龙川县| 米林县| 福安市| 西吉县| 铜梁县| 五原县| 娄底市| 福鼎市| 江门市| 黄龙县| 晋城| 惠水县| 汶上县| 台中县| 当阳市| 陆良县| 皋兰县| 定远县| 宣城市| 长沙县| 绵竹市| 阿坝县| 桑日县| 彝良县| 都江堰市| 裕民县| 皮山县| 扶余县| 青田县| 含山县| 鄂伦春自治旗| 余庆县| 安岳县| 年辖:市辖区| 佛坪县| 巴东县| 临安市| 东光县|