SpringBoot10:SpringSecurity(安全)

13、SpringSecurity(安全)

參考文章:http://www.reibang.com/p/021bf547e45e

安全簡(jiǎn)介

在Web開發(fā)中,安全一直是一個(gè)非常重要的一個(gè)方面逞壁。我們之前學(xué)過一些簡(jiǎn)單的策略舌菜,過濾器宣羊,攔截器,這里的安全框架會(huì)簡(jiǎn)單一些轴猎。

功能性需求:否

做一個(gè)網(wǎng)站啊,安全應(yīng)該在什么時(shí)候考慮进萄?

應(yīng)該在應(yīng)用開發(fā)的初期就考慮進(jìn)來捻脖。如果在應(yīng)用開發(fā)的后期才考慮安全的問題,就可能陷入一個(gè)兩難的境地:一方面中鼠,應(yīng)用存在嚴(yán)重的安全漏洞可婶,無法滿足用戶的要求,并可能造成用戶的隱私數(shù)據(jù)被攻擊者竊仍汀矛渴;另一方面,應(yīng)用的基本架構(gòu)已經(jīng)確定惫搏,要修復(fù)安全漏洞具温,可能需要對(duì)系統(tǒng)的架構(gòu)做出比較重大的調(diào)整,因而需要更多的開發(fā)時(shí)間筐赔,影響應(yīng)用的發(fā)布進(jìn)程铣猩。因此,從應(yīng)用開發(fā)的第一天就應(yīng)該把安全相關(guān)的因素考慮進(jìn)來茴丰,并在整個(gè)應(yīng)用的開發(fā)過程中达皿。

市面上存在比較有名的安全框架:Shiro天吓,Spring Security!

這里需要闡述一下的是峦椰,每一個(gè)框架的出現(xiàn)都是為了解決某一問題而產(chǎn)生了失仁,那么Spring Security框架的出現(xiàn)是為了解決什么問題呢?

首先我們看一下它的官網(wǎng)介紹:Spring Security官網(wǎng) https://spring.io/projects/spring-security/

Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.

Spring Security is a framework that focuses on providing both authentication and authorization to Java applications. Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements

Spring Security是一個(gè)功能強(qiáng)大且高度可定制的身份驗(yàn)證和訪問控制框架们何。它實(shí)際上是一個(gè)保護(hù)基于spring應(yīng)用程序標(biāo)準(zhǔn)萄焦。

Spring Security是一個(gè)側(cè)重于為Java應(yīng)用程序提供身份驗(yàn)證和授權(quán)的框架。與所有的spring項(xiàng)目一樣冤竹,Spring Security真正強(qiáng)大的地方在于它可以輕松擴(kuò)展以滿足定制需求拂封。

從官網(wǎng)的介紹中可以知道這是一個(gè)權(quán)限和認(rèn)證框架。想我們之前做項(xiàng)目是沒有使用框架是怎么控制權(quán)限的鹦蠕?對(duì)于權(quán)限 一般會(huì)細(xì)分為功能權(quán)限冒签,訪問權(quán)限,和菜單權(quán)限钟病。代碼會(huì)寫的非常的繁瑣萧恕,冗余。

怎么解決之前寫權(quán)限代碼繁瑣肠阱,冗余的問題票唆,一些主流框架就應(yīng)運(yùn)而生而Spring Scecurity就是其中的一種。

Spring 是一個(gè)非常流行和成功的 Java 應(yīng)用開發(fā)框架屹徘。Spring Security 基于 Spring 框架走趋,提供了一套 Web 應(yīng)用安全性的完整解決方案。一般來說噪伊,Web 應(yīng)用的安全性包括用戶認(rèn)證(Authentication)和用戶授權(quán)(Authorization)兩個(gè)部分簿煌。用戶認(rèn)證指的是驗(yàn)證某個(gè)用戶是否為系統(tǒng)中的合法主體,也就是說用戶能否訪問該系統(tǒng)鉴吹。用戶認(rèn)證一般要求用戶提供用戶名和密碼姨伟。系統(tǒng)通過校驗(yàn)用戶名和密碼來完成認(rèn)證過程。用戶授權(quán)指的是驗(yàn)證某個(gè)用戶是否有權(quán)限執(zhí)行某個(gè)操作豆励。在一個(gè)系統(tǒng)中夺荒,不同用戶所具有的權(quán)限是不同的。比如對(duì)一個(gè)文件來說肆糕,有的用戶只能進(jìn)行讀取般堆,而有的用戶可以進(jìn)行修改。一般來說诚啃,系統(tǒng)會(huì)為不同的用戶分配不同的角色淮摔,而每個(gè)角色則對(duì)應(yīng)一系列的權(quán)限。

對(duì)于上面提到的兩種應(yīng)用情景始赎,Spring Security 框架都有很好的支持和橙。在用戶認(rèn)證方面仔燕,Spring Security 框架支持主流的認(rèn)證方式,包括 HTTP 基本認(rèn)證魔招、HTTP 表單驗(yàn)證晰搀、HTTP 摘要認(rèn)證、OpenID 和 LDAP 等办斑。在用戶授權(quán)方面外恕,Spring Security 提供了基于角色的訪問控制和訪問控制列表(Access Control List掺炭,ACL)狈孔,可以對(duì)應(yīng)用中的領(lǐng)域?qū)ο筮M(jìn)行細(xì)粒度的控制。

實(shí)戰(zhàn)測(cè)試

實(shí)驗(yàn)環(huán)境搭建

1版确、新建一個(gè)初始的springboot項(xiàng)目web模塊蠕蚜,thymeleaf模塊

2尚洽、導(dǎo)入靜態(tài)資源

3、controller跳轉(zhuǎn)

package com.sen.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class RouterController {

    @RequestMapping({"/","/index"})
    public String index(){
        return "index";
    }

    @RequestMapping("/toLogin")
    public String toLogin(){
        return "views/login";
    }

    @RequestMapping("/level1/{id}")
    public String level1(@PathVariable("id") int id){
        return "views/level1/"+id;
    }

    @RequestMapping("/level2/{id}")
    public String level2(@PathVariable("id") int id){
        return "views/level2/"+id;
    }

    @RequestMapping("/level3/{id}")
    public String level3(@PathVariable("id") int id){
        return "views/level3/"+id;
    }
}

4靶累、測(cè)試環(huán)境是否ok

認(rèn)識(shí)SpringSecurity

Spring Security 是針對(duì)Spring項(xiàng)目的安全框架腺毫,也是Spring Boot底層安全模塊默認(rèn)的技術(shù)選型,他可以實(shí)現(xiàn)強(qiáng)大的Web安全控制挣柬,對(duì)于安全控制潮酒,我們僅需要引入spring-boot-starter-security 模塊,進(jìn)行少量的配置凛忿,即可實(shí)現(xiàn)強(qiáng)大的安全管理澈灼!

記住幾個(gè)類:

  • WebSecurityConfigurerAdapter:自定義Security策略
  • AuthenticationManagerBuilder:自定義認(rèn)證策略
  • @EnableWebSecurity:開啟WebSecurity模式

Spring Security的兩個(gè)主要目標(biāo)是 “認(rèn)證” 和 “授權(quán)”(訪問控制)。

“認(rèn)證”(Authentication)

身份驗(yàn)證是關(guān)于驗(yàn)證您的憑據(jù)店溢,如用戶名/用戶ID和密碼,以驗(yàn)證您的身份委乌。

身份驗(yàn)證通常通過用戶名和密碼完成床牧,有時(shí)與身份驗(yàn)證因素結(jié)合使用。

“授權(quán)” (Authorization)

授權(quán)發(fā)生在系統(tǒng)成功驗(yàn)證您的身份后遭贸,最終會(huì)授予您訪問資源(如信息戈咳,文件,數(shù)據(jù)庫壕吹,資金著蛙,位置,幾乎任何內(nèi)容)的完全權(quán)限耳贬。

這個(gè)概念是通用的踏堡,而不是只在Spring Security 中存在。

認(rèn)證和授權(quán)

目前咒劲,我們的測(cè)試環(huán)境顷蟆,是誰都可以訪問的诫隅,我們使用 Spring Security 增加上認(rèn)證和授權(quán)的功能

1、引入 Spring Security 模塊

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

2帐偎、編寫 Spring Security 配置類

參考官網(wǎng):https://spring.io/projects/spring-security

查看我們自己項(xiàng)目中的版本逐纬,找到對(duì)應(yīng)的幫助文檔:

https://docs.spring.io/spring-security/site/docs/5.4.5/reference/html5/#jc

3、編寫基礎(chǔ)配置類

package com.sen.config;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

//開啟WebSecurity模式
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    }
}

4削樊、定制請(qǐng)求的授權(quán)規(guī)則

//鏈?zhǔn)骄幊?@Override
protected void configure(HttpSecurity http) throws Exception {

    //首頁所有人都可以訪問豁生,功能頁只對(duì)有權(quán)限的人才能訪問
    http.authorizeRequests()
        .antMatchers("/").permitAll()
        .antMatchers("/level1/**").hasRole("vip1")
        .antMatchers("/level2/**").hasRole("vip2")
        .antMatchers("/level3/**").hasRole("vip3");
}

5、測(cè)試一下:發(fā)現(xiàn)除了首頁都進(jìn)不去了漫贞!因?yàn)槲覀兡壳皼]有登錄的角色甸箱,因?yàn)檎?qǐng)求需要登錄的角色擁有對(duì)應(yīng)的權(quán)限才可以!

6绕辖、在configure()方法中加入以下配置摇肌,開啟自動(dòng)配置的登錄功能!

// 開啟自動(dòng)配置的登錄功能
// /login 請(qǐng)求來到登錄頁
// /login?error 重定向到這里表示登錄失敗
http.formLogin();

7仪际、測(cè)試一下:發(fā)現(xiàn)围小,沒有權(quán)限的時(shí)候,會(huì)跳轉(zhuǎn)到登錄的頁面树碱!

8肯适、查看剛才登錄頁的注釋信息;

我們可以定義認(rèn)證規(guī)則成榜,重寫configure(AuthenticationManagerBuilder auth)方法

    //權(quán)限認(rèn)證
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //這些數(shù)據(jù)正常應(yīng)該從數(shù)據(jù)庫里面拿
        //在內(nèi)存中拿框舔,也可以在jdbc中拿,我們這里是用內(nèi)存去拿
        //定義權(quán)限認(rèn)證
        auth.inMemoryAuthentication()
![](https://upload-images.jianshu.io/upload_images/25821767-ce9c44a497388120.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
                .withUser("ergou").password("123456").roles("vip2","vip3")
                .and()
                .withUser("root").password("123456").roles("vip1","vip2","vip3")
                .and()
                .withUser("guest").password("123456").roles("vip1");
    }

9赎婚、測(cè)試刘绣,我們可以使用這些賬號(hào)登錄進(jìn)行測(cè)試挣输!發(fā)現(xiàn)會(huì)報(bào)錯(cuò)纬凤!

10、原因撩嚼,我們要將前端傳過來的密碼進(jìn)行某種方式加密停士,否則就無法登錄,修改代碼

//權(quán)限認(rèn)證完丽,在springboot 2.1.x中可以直接使用
//密碼編碼:PasswordEncoder
//Spring security 5.0中新增了多種加密方式恋技,也改變了密碼的格式。
//要想我們的項(xiàng)目還能夠正常登陸逻族,需要修改一下configure中的代碼蜻底。我們要將前端傳過來的密碼進(jìn)行某種方式加密
//spring security 官方推薦的是使用bcrypt加密方式。
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    //這些數(shù)據(jù)正常應(yīng)該從數(shù)據(jù)庫里面拿
    //在內(nèi)存中拿瓷耙,也可以在jdbc中拿朱躺,我們這里是用內(nèi)存去拿
    //定義權(quán)限認(rèn)證
    auth.inMemoryAuthentication()
        .withUser("ergou").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
        .and()
        .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
        .and()
        .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
}

11刁赖、測(cè)試,發(fā)現(xiàn)长搀,登錄成功宇弛,并且每個(gè)角色只能訪問自己認(rèn)證下的規(guī)則!搞定

現(xiàn)在用jdbc實(shí)現(xiàn)一下授權(quán)

jdbc 授權(quán)

1源请、導(dǎo)入依賴

        <!--thymeleaf依賴-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

        <!--jdbc依賴-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--druid依賴-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.5</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

2枪芒、編寫配置,整合jdbc谁尸、druid舅踪、mybatis

#關(guān)閉thymeleaf緩存
spring:
  thymeleaf:
    cache: false

#配置數(shù)據(jù)源
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3308/mybatis?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

    #Spring Boot 默認(rèn)是不注入這些屬性值的,需要自己綁定
    #druid 數(shù)據(jù)源專有配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    #配置監(jiān)控統(tǒng)計(jì)攔截的filters良蛮,stat:監(jiān)控統(tǒng)計(jì)抽碌、log4j:日志記錄、wall:防御sql注入
    #如果允許時(shí)報(bào)錯(cuò)  java.lang.ClassNotFoundException: org.apache.log4j.Priority
    #則導(dǎo)入 log4j 依賴即可决瞳,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
#配置mybatis
mybatis:
  type-aliases-package: com.sen.pojo
  mapper-locations: classpath:mybatis/mapper/*.xml

3货徙、創(chuàng)建實(shí)體類

@Data
@AllArgsConstructor
@NoArgsConstructor
public class user {
    private Integer id;
    private String name;
    private String password;
}

4、創(chuàng)建數(shù)據(jù)庫皮胡、表

5痴颊、編寫Mapper接口和mapper.xml

package com.sen.mapper;

import com.sen.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import java.util.List;

@Mapper
@Repository
public interface UserMapper {

    List<User> getAll();
    User getUserByName(String name);
}

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.sen.mapper.UserMapper">

    <resultMap id="userMap" type="User">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="password" column="pwd"/>
    </resultMap>

    <select id="getAll" resultMap="userMap">
        select * from mybatis.user;
    </select>

    <select id="getUserByName" resultMap="userMap" parameterType="String">
        select * from mybatis.user where name = #{name};
    </select>
</mapper>

6、測(cè)試mapper接口

6屡贺、自定義UserService進(jìn)行權(quán)限驗(yàn)證

package com.sen.security.service;

import com.sen.mapper.UserMapper;
import com.sen.pojo.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

@Service
public class UserService implements UserDetailsService {

    private final static Logger LOGGER = LoggerFactory.getLogger(UserService.class);

    @Autowired
    UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        LOGGER.info("進(jìn)入service蠢棱,用戶名為:"+username);
        if (!StringUtils.hasLength(username)){
            throw new UsernameNotFoundException("請(qǐng)輸入用戶名!");
        }
        List<SimpleGrantedAuthority> list = new ArrayList<>();
        User user = userMapper.getUserByName(username);
        for (String s : user.getRoles().split("-")) {
            s = "ROLE_" + s;
            list.add(new SimpleGrantedAuthority(s));

        }
        return new org.springframework.security.core.userdetails.User(user.getName(),new BCryptPasswordEncoder().encode( user.getPassword()),list);
    }
}

由于sercurity默認(rèn)的role格式是ROLE_ + role甩栈,所以此處擴(kuò)展泻仙,而不用保存在數(shù)據(jù)庫中

7、再將它注入將認(rèn)證規(guī)則修改如下

    //權(quán)限認(rèn)證量没,在springboot 2.1.x中可以直接使用
    //密碼編碼:PasswordEncoder
    //Spring security 5.0中新增了多種加密方式饰豺,也改變了密碼的格式。
    //要想我們的項(xiàng)目還能夠正常登陸允蜈,需要修改一下configure中的代碼。我們要將前端傳過來的密碼進(jìn)行某種方式加密
    //spring security 官方推薦的是使用bcrypt加密方式蒿柳。
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //這些數(shù)據(jù)正常應(yīng)該從數(shù)據(jù)庫里面拿
        //在內(nèi)存中拿饶套,也可以在jdbc中拿,我們這里是用內(nèi)存去拿
        //定義權(quán)限認(rèn)證
        // auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
        //         .withUser("ergou").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
        //         .and()
        //         .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
        //         .and()
        //         .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
        auth.userDetailsService(userService).passwordEncoder(new BCryptPasswordEncoder());
    }

然后我們運(yùn)行程序垒探,輸入我們的用戶名密碼發(fā)現(xiàn)登錄成功妓蛮。

注銷與記住我

注銷

1、開啟自動(dòng)配置的注銷的功能

        //注銷,開啟注銷功能
        http.logout()
                .logoutSuccessUrl("/");//登錄成功后跳轉(zhuǎn)到首頁

上述開源看源碼得知

     *  &#064;Override
     *  protected void configure(HttpSecurity http) throws Exception {
     *      http.authorizeRequests().antMatchers(&quot;/**&quot;).hasRole(&quot;USER&quot;).and().formLogin()
     *              .and()
     *              // sample logout customization
     *              .logout().deleteCookies(&quot;remove&quot;).invalidateHttpSession(false)
     *              .logoutUrl(&quot;/custom-logout&quot;).logoutSuccessUrl(&quot;/logout-success&quot;);
     *  }
     *
     *  &#064;Override
     *  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
     *      auth.inMemoryAuthentication().withUser(&quot;user&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;);
     *  }
     * }
     * </pre>
     * @return the {@link LogoutConfigurer} for further customizations
     * @throws Exception
     */
    public LogoutConfigurer<HttpSecurity> logout() throws Exception {
        return getOrApply(new LogoutConfigurer<>());
    }

2圾叼、我們?cè)谇岸烁蚩耍黾右粋€(gè)注銷的按鈕捺癞,index.html 導(dǎo)航欄中

<a class="item" th:href="@{/logout}">
   <i class="address card icon"></i> 注銷
</a>

3、我們可以去測(cè)試一下构挤,登錄成功后點(diǎn)擊注銷髓介,發(fā)現(xiàn)注銷完畢會(huì)跳轉(zhuǎn)到登錄頁面!

4筋现、但是唐础,我們想讓他注銷成功后,依舊可以跳轉(zhuǎn)到首頁矾飞,該怎么處理呢一膨?

// .logoutSuccessUrl("/"); 注銷成功來到首頁
http.logout().logoutSuccessUrl("/");

5、測(cè)試洒沦,注銷完畢后豹绪,發(fā)現(xiàn)跳轉(zhuǎn)到首頁OK

6、我們現(xiàn)在又來一個(gè)需求:用戶沒有登錄的時(shí)候申眼,導(dǎo)航欄上只顯示登錄按鈕瞒津,用戶登錄之后,導(dǎo)航欄可以顯示登錄的用戶信息及注銷按鈕豺型!還有就是仲智,比如kuangshen這個(gè)用戶,它只有 vip2姻氨,vip3功能钓辆,那么登錄則只顯示這兩個(gè)功能,而vip1的功能菜單不顯示肴焊!這個(gè)就是真實(shí)的網(wǎng)站情況了前联!該如何做呢?

我們需要結(jié)合thymeleaf中的一些功能

sec:authorize="isAuthenticated()":是否認(rèn)證登錄娶眷!來顯示不同的頁面

Maven依賴:

<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity4 -->
<dependency>
   <groupId>org.thymeleaf.extras</groupId>
   <artifactId>thymeleaf-extras-springsecurity5</artifactId>
   <version>3.0.4.RELEASE</version>
</dependency>

7似嗤、修改我們的 前端頁面

  1. 導(dǎo)入命名空間

  2. xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"
    
  3. 修改導(dǎo)航欄,增加認(rèn)證判斷

  4. <!--登錄注銷-->
    <div class="right menu">
    
       <!--如果未登錄-->
       <div sec:authorize="!isAuthenticated()">
           <a class="item" th:href="@{/login}">
               <i class="address card icon"></i> 登錄
           </a>
       </div>
    
       <!--如果已登錄-->
       <div sec:authorize="isAuthenticated()">
           <a class="item">
               <i class="address card icon"></i>
              用戶名:<span sec:authentication="principal.username"></span>
              角色:<span sec:authentication="principal.authorities"></span>
           </a>
       </div>
    
       <div sec:authorize="isAuthenticated()">
           <a class="item" th:href="@{/logout}">
               <i class="address card icon"></i> 注銷
           </a>
       </div>
    </div>
    

8届宠、重啟測(cè)試烁落,我們可以登錄試試看,登錄成功后確實(shí)豌注,顯示了我們想要的頁面伤塌;

9、如果注銷404了轧铁,就是因?yàn)樗J(rèn)防止csrf跨站請(qǐng)求偽造每聪,因?yàn)闀?huì)產(chǎn)生安全問題,我們可以將請(qǐng)求改為post表單提交,或者在spring security中關(guān)閉csrf功能药薯;我們?cè)囋嚕涸?配置中增加 http.csrf().disable();

http.csrf().disable();//關(guān)閉csrf功能:跨站請(qǐng)求偽造,默認(rèn)只能通過post方式提交logout請(qǐng)求
http.logout().logoutSuccessUrl("/");

10绑洛、我們繼續(xù)將下面的角色功能塊認(rèn)證完成!

<!-- sec:authorize="hasRole('vip1')" -->
<div class="column" sec:authorize="hasRole('vip1')">
   <div class="ui raised segment">
       <div class="ui">
           <div class="content">
               <h5 class="content">Level 1</h5>
               <hr>
               <div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div>
               <div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div>
               <div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></div>
           </div>
       </div>
   </div>
</div>

<div class="column" sec:authorize="hasRole('vip2')">
   <div class="ui raised segment">
       <div class="ui">
           <div class="content">
               <h5 class="content">Level 2</h5>
               <hr>
               <div><a th:href="@{/level2/1}"><i class="bullhorn icon"></i> Level-2-1</a></div>
               <div><a th:href="@{/level2/2}"><i class="bullhorn icon"></i> Level-2-2</a></div>
               <div><a th:href="@{/level2/3}"><i class="bullhorn icon"></i> Level-2-3</a></div>
           </div>
       </div>
   </div>
</div>

<div class="column" sec:authorize="hasRole('vip3')">
   <div class="ui raised segment">
       <div class="ui">
           <div class="content">
               <h5 class="content">Level 3</h5>
               <hr>
               <div><a th:href="@{/level3/1}"><i class="bullhorn icon"></i> Level-3-1</a></div>
               <div><a th:href="@{/level3/2}"><i class="bullhorn icon"></i> Level-3-2</a></div>
               <div><a th:href="@{/level3/3}"><i class="bullhorn icon"></i> Level-3-3</a></div>
           </div>
       </div>
   </div>
</div>

11童本、測(cè)試一下真屯!

12、權(quán)限控制和注銷搞定巾陕!

記住我

現(xiàn)在的情況讨跟,我們只要登錄之后,關(guān)閉瀏覽器鄙煤,再登錄晾匠,就會(huì)讓我們重新登錄,但是很多網(wǎng)站的情況梯刚,就是有一個(gè)記住密碼的功能凉馆,這個(gè)該如何實(shí)現(xiàn)呢?很簡(jiǎn)單

1亡资、開啟記住我功能

//定制請(qǐng)求的授權(quán)規(guī)則
@Override
protected void configure(HttpSecurity http) throws Exception {
//澜共。。锥腻。嗦董。。瘦黑。京革。。幸斥。匹摇。。
   //記住我
   http.rememberMe();
}

2甲葬、我們?cè)俅螁?dòng)項(xiàng)目測(cè)試一下廊勃,發(fā)現(xiàn)登錄頁多了一個(gè)記住我功能,我們登錄之后關(guān)閉 瀏覽器经窖,然后重新打開瀏覽器訪問坡垫,發(fā)現(xiàn)用戶依舊存在!

思考:如何實(shí)現(xiàn)的呢画侣?其實(shí)非常簡(jiǎn)單

我們可以查看瀏覽器的cookie

3葛虐、我們點(diǎn)擊注銷的時(shí)候,可以發(fā)現(xiàn)棉钧,spring security 幫我們自動(dòng)刪除了這個(gè) cookie

4、結(jié)論:登錄成功后,將cookie發(fā)送給瀏覽器保存宪卿,以后登錄帶上這個(gè)cookie的诵,只要通過檢查就可以免登錄了。如果點(diǎn)擊注銷佑钾,則會(huì)刪除這個(gè)cookie西疤,具體的原理我們?cè)贘avaWeb階段都講過了,這里就不在多說了休溶!

定制登錄頁

定制登錄頁

現(xiàn)在這個(gè)登錄頁面都是spring security 默認(rèn)的代赁,怎么樣可以使用我們自己寫的Login界面呢?

1兽掰、在剛才的登錄頁配置后面指定 loginpage

http.formLogin().loginPage("/toLogin");

2芭碍、然后前端也需要指向我們自己定義的 login請(qǐng)求

<a class="item" th:href="@{/toLogin}">
   <i class="address card icon"></i> 登錄
</a>

3、我們登錄孽尽,需要將這些信息發(fā)送到哪里窖壕,我們也需要配置,login.html 配置提交請(qǐng)求及方式杉女,方式必須為post:

     * <ul>
     * <li>/login GET - the login form</li>
     * <li>/login POST - process the credentials and if valid authenticate the user</li>
     * <li>/login?error GET - redirect here for failed authentication attempts</li>
     * <li>/login?logout GET - redirect here after successfully logging out</li>
     * </ul>
<form th:action="@{/login}" method="post">
    <div class="field">
        <label>Username</label>
        <div class="ui left icon input">
            <input type="text" placeholder="Username" name="username">
            <i class="user icon"></i>
        </div>
    </div>
    <div class="field">
        <label>Password</label>
        <div class="ui left icon input">
            <input type="password" name="password">
            <i class="lock icon"></i>
        </div>
    </div>
    <input type="submit" class="ui blue submit button"/>
</form>

4瞻讽、這個(gè)請(qǐng)求提交上來,我們還需要驗(yàn)證處理熏挎,怎么做呢速勇?我們可以查看formLogin()方法的源碼!我們配置接收登錄的用戶名和密碼的參數(shù)坎拐!

http.formLogin()
  .usernameParameter("username")
  .passwordParameter("password")
  .loginPage("/toLogin")
  .loginProcessingUrl("/login"); // 登陸表單提交請(qǐng)求

5烦磁、在登錄頁增加記住我的多選框

<div class="field">
    <input type="checkbox" name="remember"> 記住我
</div>

6、后端驗(yàn)證處理廉白!

//定制記住我的參數(shù)个初!
http.rememberMe().rememberMeParameter("remember");

7、測(cè)試猴蹂,OK

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末院溺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子磅轻,更是在濱河造成了極大的恐慌珍逸,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件聋溜,死亡現(xiàn)場(chǎng)離奇詭異谆膳,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)撮躁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門漱病,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事杨帽±齑” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵注盈,是天一觀的道長(zhǎng)晃危。 經(jīng)常有香客問我,道長(zhǎng)老客,這世上最難降的妖魔是什么僚饭? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮胧砰,結(jié)果婚禮上鳍鸵,老公的妹妹穿的比我還像新娘。我一直安慰自己朴则,他們只是感情好权纤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著乌妒,像睡著了一般汹想。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上撤蚊,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天古掏,我揣著相機(jī)與錄音,去河邊找鬼侦啸。 笑死槽唾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的光涂。 我是一名探鬼主播庞萍,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼忘闻!你這毒婦竟也來了钝计?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤齐佳,失蹤者是張志新(化名)和其女友劉穎私恬,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體炼吴,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡本鸣,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了硅蹦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荣德。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡闷煤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出命爬,到底是詐尸還是另有隱情曹傀,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布饲宛,位于F島的核電站,受9級(jí)特大地震影響嗜价,放射性物質(zhì)發(fā)生泄漏艇抠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一久锥、第九天 我趴在偏房一處隱蔽的房頂上張望家淤。 院中可真熱鬧,春花似錦瑟由、人聲如沸絮重。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽青伤。三九已至,卻和暖如春殴瘦,著一層夾襖步出監(jiān)牢的瞬間狠角,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工蚪腋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留丰歌,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓屉凯,卻偏偏與公主長(zhǎng)得像立帖,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子悠砚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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