手把手帶你入門 Spring Security

Spring Security 由于配置復(fù)雜刃麸,一直被人所詬病,所以對(duì)于 SSM 框架的項(xiàng)目來(lái)說(shuō),輕量的 Shiro 顯然更適合它。然而 Spring Boot 的橫空出世打破了這個(gè)局面钩述,Spring Boot 通過(guò)自動(dòng)配置,使得開發(fā)者在 Spring Boot 中使用 Spring Security 變得非常簡(jiǎn)單∧滤椋現(xiàn)如今的 Spring Boot 應(yīng)用若是想集成安全框架牙勘,基本都會(huì)毫不猶豫地選擇 Spring Security。

HelloWorld 案例

首先通過(guò)一個(gè)案例來(lái)感受一下在 Spring Boot 中如何使用 Spring Security所禀,創(chuàng)建一個(gè) Spring Boot 應(yīng)用方面,并引入依賴:

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

編寫一個(gè)控制器:

@RestController
public class TestController {

    @RequestMapping("hello")
    public String hello(){
        return "Hello SpringSecurity!";
    }
}

然后直接啟動(dòng)項(xiàng)目,訪問(wèn) http://localhost:8080/login

結(jié)果打開的是一個(gè)登錄頁(yè)面色徘,其實(shí)這時(shí)候我們的請(qǐng)求已經(jīng)被保護(hù)起來(lái)了葡幸,要想訪問(wèn),得先登錄贺氓。

在這個(gè)案例中僅僅是引入了一個(gè) Spring Security 的 starter 啟動(dòng)器蔚叨,沒(méi)有做任何的配置,而項(xiàng)目已經(jīng)具有了權(quán)限認(rèn)證辙培。

現(xiàn)在我們來(lái)登錄一下:

手把手帶你入門 Spring Security

Spring Security 默認(rèn)提供了一個(gè)用戶名為 user 的用戶蔑水,其密碼在控制臺(tái)可以找到:

成功登錄以后就可以正常訪問(wèn)了:

手把手帶你入門 Spring Security

用戶認(rèn)證

剛才的案例中我們使用的是 Spring Security 提供的用戶名和密碼進(jìn)行登錄的,那么該如何配置自己的用戶名和密碼呢扬蕊?

按照 Spring Boot 的自動(dòng)配置原理搀别,它肯定為其編寫了一個(gè) XXXProperties 的類作為配置,來(lái)查找一下:

手把手帶你入門 Spring Security

找到了這個(gè)類就知道該如何配置了:

通過(guò)這幾個(gè)地方尾抑,我們能夠知道一些信息歇父,配置必須使用 spring.security 前綴,然后可以看到 Spring Security 為我們初始化的用戶名和密碼再愈,所以若是想修改配置榜苫,則應(yīng)使用 spring.security.user.name 和 spring.security.user.password。

在 Spring Boot 的配置文件中進(jìn)行如下配置:

spring:
  security:
    user:
      name: wwj
      password: 123

此時(shí)啟動(dòng)項(xiàng)目翎冲,將只能通過(guò)自己配置的用戶名和密碼登錄垂睬。

當(dāng)然還可以通過(guò)配置類的方式進(jìn)行配置,創(chuàng)建一個(gè)配置類繼承 WebSecurityConfigurerAdapter:

@Configuration
@Component
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //對(duì)密碼進(jìn)行加密
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String password = passwordEncoder.encode("123");
        auth.inMemoryAuthentication().withUser("wwj").password(password).roles("admin");
    }
}

重新啟動(dòng)項(xiàng)目測(cè)試一下。會(huì)發(fā)現(xiàn)登錄不上驹饺,觀察控制臺(tái):

這是因?yàn)槲覀冊(cè)趯?duì)密碼加密的時(shí)候使用到了 BCryptPasswordEncoder 對(duì)象钳枕,而容器中并沒(méi)有這個(gè)對(duì)象,所以我們還需要?jiǎng)?chuàng)建該對(duì)象:

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

再次重新啟動(dòng)一切正常赏壹。

我們還可以采取自定義實(shí)現(xiàn)類的方式來(lái)實(shí)現(xiàn)鱼炒,首先仍然是創(chuàng)建配置類:

@Configuration
@Component
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(getPasswordEncoder());
    }

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

此時(shí)我們需要實(shí)現(xiàn) UserDetailsService 接口:

@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        String password = new BCryptPasswordEncoder().encode("123");
        //權(quán)限集合
        List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
        return new User("wwj", password, authorities);
    }
}

查詢數(shù)據(jù)庫(kù)完成登錄認(rèn)證

剛才我們對(duì)案例進(jìn)行了進(jìn)一步的操作,即通過(guò)自己指定的用戶名和密碼進(jìn)行認(rèn)證蝌借,然而真實(shí)的生產(chǎn)環(huán)境中昔瞧,認(rèn)證的過(guò)程肯定是要經(jīng)過(guò)數(shù)據(jù)庫(kù)的,用戶輸入用戶名和密碼骨望,然后進(jìn)行數(shù)據(jù)庫(kù)查詢驗(yàn)證登錄硬爆,接下來(lái)就實(shí)現(xiàn)一下這個(gè)過(guò)程欣舵。

首先引入依賴:

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.4</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

創(chuàng)建數(shù)據(jù)表:

create database springsecurity;

use springsecurity;

create table user(
 id int primary key auto_increment,
    username varchar(20),
    password varchar(20)
);

insert into user values(null,'zhangsan','123');
insert into user values(null,'lisi','456');

然后就可以使用 MyBatis 的逆向工程生成一下實(shí)體類擎鸠、Mapper 接口和 Mapper 配置文件,之后要在 Spring Boot 的配置文件中進(jìn)行 MyBatis 的相關(guān)配置:

spring:
  datasource:
    url: jdbc:mysql:///springsecurity?serverTimezone=GMT%2B8
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456

mybatis:
  type-aliases-package: com.wwj.springsecuritydemo.bean
  mapper-locations: classpath:mappers/*.xml

最后在啟動(dòng)類上添加注解:

@SpringBootApplication
@MapperScan("com.wwj.springsecuritydemo.dao")
public class SpringsecuritydemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringsecuritydemoApplication.class, args);
    }

}

這樣 MyBatis 就整合完成了缘圈,接下來(lái)是 Spring Security 的相關(guān)配置劣光,還記得我們是如何實(shí)現(xiàn)自定義用戶登錄的嗎?一起回憶一下吧糟把,首先需要一個(gè)配置類:

@Configuration
@Component
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(getPasswordEncoder());
    }

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

該配置類中注入了一個(gè) UserDetailsService 對(duì)象绢涡,它是一個(gè)接口,所以我們需要自定義類實(shí)現(xiàn)該接口:

@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        String password = new BCryptPasswordEncoder().encode("123");
        //權(quán)限集合
        List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
        return new User("wwj", password, authorities);
    }
}

之前我們是這樣寫的遣疯,直接返回 User 對(duì)象即可雄可,這個(gè) User 對(duì)象是 Spring Security 提供的,不是我們創(chuàng)建的實(shí)體類 User缠犀。

現(xiàn)在我們就需要修改這個(gè)類:

@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        //這里的 String s 實(shí)際上是表單傳遞過(guò)來(lái)的用戶名
        //根據(jù)用戶名查詢數(shù)據(jù)表
        UserExample userExample = new UserExample();
        UserExample.Criteria criteria = userExample.createCriteria();
        criteria.andUsernameEqualTo(s);
        List<com.wwj.springsecuritydemo.bean.User> userList = userMapper.selectByExample(userExample);
        if (userList == null || userList.isEmpty()) {
            //沒(méi)有查詢到用戶数苫,認(rèn)證失敗
            throw new UsernameNotFoundException("該用戶不存在!");
        }
        //取出用戶信息
        com.wwj.springsecuritydemo.bean.User user = userList.get(0);
        String password = new BCryptPasswordEncoder().encode(user.getPassword());
        //權(quán)限集合
        List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
        return new User(user.getUsername(), password, authorities);
    }
}

首先 loadUserByUsername(String s) 方法的入?yún)?String s 實(shí)際上是表單傳遞過(guò)來(lái)的用戶名,然后通過(guò)該用戶名在數(shù)據(jù)表中查詢辨液,若查詢不到結(jié)果虐急,說(shuō)明用戶不存在,拋出異常即可滔迈;若查詢出了結(jié)果止吁,則需要將用戶信息封裝到 Spring Security 提供的 User 對(duì)象中進(jìn)行返回。

我們可以通過(guò) Debug 的方式來(lái)具體看看執(zhí)行流程燎悍,直接在第一行代碼上打個(gè)斷點(diǎn):

手把手帶你入門 Spring Security

然后以 Debug 方式啟動(dòng):

手把手帶你入門 Spring Security

當(dāng)輸入一個(gè)不存在的用戶并登錄時(shí):

手把手帶你入門 Spring Security

可以看到此時(shí)的 s 就是我們輸入的用戶名敬惦,而當(dāng)我們輸入一個(gè)正確的用戶名時(shí):

手把手帶你入門 Spring Security

loadUserByUsername() 方法同樣獲取到輸入的用戶名,

手把手帶你入門 Spring Security

如果密碼輸入錯(cuò)誤也是無(wú)法進(jìn)行登錄的谈山,這是因?yàn)?Spring Security 有著它自己的驗(yàn)證方式仁热,因?yàn)槲覀兡壳斑€是用的 Spring Security 提供的登錄頁(yè)面,所以密碼的校驗(yàn)也是由 Spring Security 自己完成的。

自定義登錄頁(yè)面

剛才我們又對(duì)案例進(jìn)行了升級(jí)抗蠢,現(xiàn)在已經(jīng)可以根據(jù)數(shù)據(jù)表中的用戶信息進(jìn)行登錄校驗(yàn)了举哟,然而 Spring Security 提供的登錄頁(yè)面過(guò)于簡(jiǎn)單屎篱,那么該如何將其替換成我們自己的登錄頁(yè)面呢敞临?

首先來(lái)到配置類,在配置類中重寫 configure(HttpSecurity http) 方法:

@Configuration
@Component
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(getPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .and()
                .authorizeRequests()
                .antMatchers("/","/hello","/user/login")//配置哪些路徑可以直接訪問(wèn)
                .permitAll()
                .anyRequest().authenticated()//攔截所有資源
                .and()
                .formLogin()
                .loginPage("/login.html")//設(shè)置登錄頁(yè)面
                .loginProcessingUrl("/user/login")//設(shè)置登錄的請(qǐng)求路徑
                .defaultSuccessUrl("/user/index")//設(shè)置登錄成功后的跳轉(zhuǎn)路徑
                .permitAll()
                .and()
                .csrf().disable();//禁用 csrf
    }

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

此時(shí)就可以通過(guò) configure(HttpSecurity http) 方法的入?yún)?http 進(jìn)行相關(guān)的設(shè)置遭笋,需要注意的是秽褒,其中 loginProcessingUrl 方法設(shè)置的是登錄的請(qǐng)求路徑壶硅,即登錄表單的 action 屬性需要與其對(duì)應(yīng),登錄表單如下:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/user/login" method="post">
        用戶名:<input type="text" name="username"/><br>
        密碼:<input type="password" name="password"/><br>
        <input type="submit" value="登錄">
    </form>
</body>
</html>

這里注意了销斟,表單中的用戶名和密碼輸入框的 name 屬性值必須為 username 和 password庐椒,否則 Spring Security 就無(wú)法獲取到這兩個(gè)參數(shù),也就無(wú)法幫助你完成登錄校驗(yàn)了蚂踊。

最后編寫幾個(gè)控制方法進(jìn)行測(cè)試:

@RestController
public class TestController {

    @RequestMapping("/hello")
    public String hello(){
        return "Hello SpringSecurity!";
    }

    @GetMapping("/user/index")
    public String index(){
        return "Hello Index!";
    }

    @GetMapping("/user/test")
    public String test(){
        return "Test!";
    }
}

此時(shí)啟動(dòng)項(xiàng)目约谈,我們可以直接來(lái)訪問(wèn) http://localhost:8080/hello

訪問(wèn)成功,這是因?yàn)槲覀兣渲昧?/hello 請(qǐng)求可以直接訪問(wèn)犁钟,那么接下來(lái)測(cè)試一下 http://localhost:8080/user/index

手把手帶你入門 Spring Security

可以看到棱诱,因?yàn)?/user/index 是被保護(hù)的,所以 Spring Security 幫助我們跳轉(zhuǎn)到了登錄頁(yè)面涝动,此時(shí)我們進(jìn)行登錄即可迈勋,登錄成功后就能正常訪問(wèn)了:

手把手帶你入門 Spring Security

若是直接訪問(wèn)登錄頁(yè)面:

手把手帶你入門 Spring Security

則登錄后會(huì)跳轉(zhuǎn)至 defaultSuccessUrl 方法配置的請(qǐng)求路徑中。

基于權(quán)限訪問(wèn)控制

前面我們已經(jīng)實(shí)現(xiàn)了資源的訪問(wèn)保護(hù)醋粟,然而并不是所有登錄認(rèn)證通過(guò)后的用戶都可以訪問(wèn)系統(tǒng)中的所有資源靡菇,我們應(yīng)該對(duì)用戶進(jìn)行權(quán)限的劃分,比如劃分為普通管理員和超級(jí)管理員權(quán)限米愿,那么普通管理員能夠操作的資源就肯定要少于超級(jí)管理員厦凤。

接下來(lái)就來(lái)看看在 Spring Security 中是如何實(shí)現(xiàn)權(quán)限訪問(wèn)控制的:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .and()
        .authorizeRequests()
        .antMatchers("/","/hello")
        .permitAll()
        //設(shè)置權(quán)限,當(dāng)前用戶必須有 admin 權(quán)限才能訪問(wèn)該路徑
        .antMatchers("/user/index").hasAuthority("admin")
        .anyRequest().authenticated()
        .and()
        .formLogin()
        .loginPage("/login.html")
        .loginProcessingUrl("/user/login")
        .defaultSuccessUrl("/user/index")
        .permitAll()
        .and()
        .csrf().disable();
}

其實(shí)非常簡(jiǎn)單吗货,在原來(lái)的配置基礎(chǔ)上添加 hasAuthority 方法泳唠,該方法會(huì)判斷用戶是否擁有指定的權(quán)限,此時(shí)表示 /user/index 請(qǐng)求必須擁有 admin 權(quán)限才能夠訪問(wèn)宙搬,直接啟動(dòng)項(xiàng)目測(cè)試一下:

手把手帶你入門 Spring Security

可以看到我們是能夠直接登錄成功的笨腥,這是因?yàn)樵?MyUserDetailsService 中我們?yōu)槊總€(gè)用戶都設(shè)置了 admin 權(quán)限:

手把手帶你入門 Spring Security

下面我們修改一下權(quán)限:

List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("ord");

重新啟動(dòng)項(xiàng)目:

手把手帶你入門 Spring Security

我們可以看到網(wǎng)頁(yè)報(bào)錯(cuò)了,顯示的是 403勇垛,即無(wú)權(quán)限訪問(wèn)脖母,當(dāng)然了,這個(gè)頁(yè)面我們也是可以進(jìn)行設(shè)置了闲孤。

有時(shí)候的一些資源是可以提供多個(gè)權(quán)限的用戶訪問(wèn)的谆级,這時(shí)我們就需要使用 hasAnyAuthoirty 方法為請(qǐng)求路徑設(shè)置多個(gè)權(quán)限:

//設(shè)置權(quán)限,當(dāng)前用戶必須有 admin 權(quán)限才能訪問(wèn)該路徑
.antMatchers("/user/test").hasAnyAuthority("admin,manager")

此時(shí) admin 和 manager 權(quán)限的用戶均可以訪問(wèn) /user/test 請(qǐng)求。

基于角色訪問(wèn)控制

角色與權(quán)限類似肥照,但又有些許不同脚仔,通常在一個(gè)系統(tǒng)中,權(quán)限不會(huì)直接分配給用戶舆绎,而是指定用戶為某個(gè)角色或某些角色鲤脏,并由這些角色來(lái)決定用戶具有哪些權(quán)限。比如在一個(gè)服裝后臺(tái)系統(tǒng)中吕朵,作為銷售角色的用戶猎醇,它就只有瀏覽衣服庫(kù)存和價(jià)錢的權(quán)限。

而在 Spring Security 中努溃,可以使用 hasRole 方法為某個(gè)請(qǐng)求設(shè)置角色訪問(wèn)控制:

//設(shè)置角色硫嘶,當(dāng)前用戶必須為 sale 角色才能訪問(wèn)該路徑
.antMatchers("/user/test").hasRole("sale")

此時(shí)表示 /user/test 請(qǐng)求只有 sale 角色的用戶才能訪問(wèn),在 MyUserDetailsService 中進(jìn)行設(shè)置:

List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_sale");

需要注意的是 hasRole 方法底層會(huì)為我們的角色名拼接一個(gè) ROLE_ 前綴梧税,所以在為用戶設(shè)置角色時(shí)需要加上該前綴:

private static String hasRole(String role) {
    Assert.notNull(role, "role cannot be null");
    if (role.startsWith("ROLE_")) {
        throw new IllegalArgumentException("role should not start with 'ROLE_' since it is automatically inserted. Got '" + role + "'");
    } else {
        return "hasRole('ROLE_" + role + "')";
    }
}

它同樣也可以設(shè)置多個(gè)角色沦疾,使用 hasAnyRole 方法即可,用法與 hasAnyAuthority 類似贡蓖。

自定義權(quán)限不足頁(yè)面

在前面我們實(shí)現(xiàn)了基于權(quán)限和角色的訪問(wèn)控制曹鸠,當(dāng)權(quán)限不足時(shí)煌茬,頁(yè)面會(huì)顯示 403斥铺,這種錯(cuò)誤對(duì)用戶來(lái)說(shuō)是不友好的,為此坛善,我們應(yīng)該自定義該頁(yè)面晾蜘,并讓其在權(quán)限不足,無(wú)法訪問(wèn)時(shí)跳轉(zhuǎn)至我們自己的頁(yè)面眠屎。

實(shí)現(xiàn)非常簡(jiǎn)單剔交,直接在 configure 方法中進(jìn)行配置即可:

//配置 403 頁(yè)面
http.exceptionHandling().accessDeniedPage("/403.html");

編寫一個(gè)頁(yè)面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1 style="color: red">您無(wú)權(quán)訪問(wèn)!</h1>
</body>
</html>

手把手帶你入門 Spring Security

注解的使用

Spring Security 還支持注解的方式配置,下面介紹常用的五個(gè)注解:

  • @Secured
  • @PreAuthorize
  • @PostAuthorize
  • @PreFilter
  • @PostFilter

@Secured 注解用于判斷用戶是否為某個(gè)角色改衩,注意這里也要加上 ROLE_ 前綴岖常,使用該注解前需要在啟動(dòng)類上添加一個(gè)注解:

@SpringBootApplication
@MapperScan("com.wwj.springsecuritydemo.dao")
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SpringsecuritydemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringsecuritydemoApplication.class, args);
    }
}

此時(shí)在控制方法上添加該注解即可:

@GetMapping("/testSecured")
@Secured({"ROLE_sale","ROLE_manager"})
public String testSecured(){
    return "testSecured";
}

這里表示只有用戶為 sale 或 manager 角色時(shí)才能訪問(wèn) /testSecured 請(qǐng)求。

@PreAuthorize 注解適合進(jìn)入方法前的權(quán)限驗(yàn)證葫督,使用該注解前需要在啟動(dòng)上添加 @EnableGlobalMethodSecurity(prePostEnabled = true) 注解:

@GetMapping("/testPreAuthorize")
@PreAuthorize("hasAnyAuthority('admin')")
public String testPreAuthorize() {
    return "testSecured";
}

@PostAuthorize 注解會(huì)在方法執(zhí)行后再進(jìn)行權(quán)限驗(yàn)證竭鞍,適合帶有返回值的權(quán)限,它與 @PreAuthorize 的用法類似橄镜,加上不太常用偎快,這里就不做介紹了。

用戶注銷

登錄認(rèn)證之后洽胶,自然要有注銷功能晒夹,否則當(dāng)用戶準(zhǔn)備退出系統(tǒng)時(shí)會(huì)發(fā)現(xiàn)自己無(wú)法做到退出,導(dǎo)致一些安全問(wèn)題。

只需在配置類中添加如下配置即可:

//用戶注銷
http.logout().logoutUrl("/logout").logoutSuccessUrl("/login.html").permitAll();

此時(shí)已經(jīng)完成用戶注銷功能丐怯,但為了方便測(cè)試喷好,這里先創(chuàng)建一個(gè)登錄成功后跳轉(zhuǎn)的頁(yè)面 success.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>登錄成功!</h1>
    <a href="/logout" style="color: red">注銷</a>
</body>
</html>

注銷超鏈接的 href 屬性需要填寫為在配置類中配置的 logoutUrl 屬性值。

然后在配置類中將登錄成功后的跳轉(zhuǎn) url 設(shè)置為該頁(yè)面:

.defaultSuccessUrl("/success.html")//設(shè)置登錄成功后的跳轉(zhuǎn)路徑

測(cè)試一下:

手把手帶你入門 Spring Security

好了读跷,以上就是本篇文章的全部?jī)?nèi)容了绒窑,希望對(duì)你入門有幫助吧!如有錯(cuò)誤或未考慮完全的地方舔亭,望不吝賜教些膨!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市钦铺,隨后出現(xiàn)的幾起案子订雾,更是在濱河造成了極大的恐慌,老刑警劉巖矛洞,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件洼哎,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡沼本,警方通過(guò)查閱死者的電腦和手機(jī)噩峦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)抽兆,“玉大人识补,你說(shuō)我怎么就攤上這事”韬欤” “怎么了凭涂?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)贴妻。 經(jīng)常有香客問(wèn)我切油,道長(zhǎng),這世上最難降的妖魔是什么名惩? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任澎胡,我火速辦了婚禮,結(jié)果婚禮上娩鹉,老公的妹妹穿的比我還像新娘攻谁。我一直安慰自己,他們只是感情好底循,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布巢株。 她就那樣靜靜地躺著,像睡著了一般熙涤。 火紅的嫁衣襯著肌膚如雪阁苞。 梳的紋絲不亂的頭發(fā)上困檩,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音那槽,去河邊找鬼悼沿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛骚灸,可吹牛的內(nèi)容都是我干的糟趾。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼甚牲,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼义郑!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起丈钙,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤非驮,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后雏赦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體劫笙,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年星岗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了填大。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡俏橘,死狀恐怖允华,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情敷矫,我是刑警寧澤例获,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布汉额,位于F島的核電站曹仗,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蠕搜。R本人自食惡果不足惜怎茫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望妓灌。 院中可真熱鬧轨蛤,春花似錦、人聲如沸虫埂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)掉伏。三九已至缝呕,卻和暖如春澳窑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背供常。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工摊聋, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人栈暇。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓麻裁,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親源祈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子煎源,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容