SpringSecurity

准备条件

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
</dependency>
 <!--springsecurity整合thymeleaf的包-->
<dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
@Controller
public class RouterController {
    @RequestMapping({"/", "/index"})
    public String toIndex() {
        return "index";
    }

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

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

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

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

}

1、启动项目在控制台会打印如下信息

在这里插入图片描述
此时在浏览器输入http://localhost:8001,会跳转到登录页面:

默认用户名为user,密码就是控制台打印的。
在这里插入图片描述
以上信息说明SpringSecurity生效了!正确输入上面的用户和密码即可登陆将进入首页!
在这里插入图片描述

2、SpringSecurity简介

在这里插入图片描述
点击到达SpringSecurity学习文档

3、以Aop横切的方式配置javaConfig继承WebSecurityConfigurerAdapter,使用@EnableWebSecurity开启此功能,并且重写protected void configure(HttpSecurity http) throws Exception方法

授权操作

 @Override
    protected void configure(HttpSecurity http) throws Exception {
        //授权
        //首页所有的人都可以访问,功能页只有对应有权限的人才可以访问
        //请求授权的规则
       http.authorizeRequests()
               .antMatchers("/").permitAll()
               .antMatchers("/level1/**").hasRole("vip1")
               .antMatchers("/level2/**").hasRole("vip2")
               .antMatchers("/level3/**").hasRole("vip3");
    }

登陆ip地址http://localhost:8001即可直接成功访问首页

在这里插入图片描述
随便点击一个链接,出现禁止访问的提示!
在这里插入图片描述
在配置类中的方法protected void configure(HttpSecurity http) throws Exception添加“如果没有权限访问就到登陆页面” 这个登陆页面是SpringSecurity自定义的

//没有权限默认会到登陆页面
       http.formLogin();

在这里插入图片描述
在配置类中添加认证操作的方法protected void configure(AuthenticationManagerBuilder auth) throws Exception

//认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //这些数据正常是从数据库中读出的
        //从内存中认证,也可以从数据库中查询相应角色的数据进行认证
        auth.inMemoryAuthentication()
                .withUser("ml").password("123456").roles("vip1","vip2")
                .and()
                .withUser("root").password("123").roles("vip1","vip2","vip3")
                .and()
                .withUser("guest").password("1").roles("vip1");

    }

登陆iphttp://localhost:8001/访问首页,点击level1下的链接,使用
在这里插入图片描述
登陆
在这里插入图片描述
出现下面的错误!
在这里插入图片描述
解决方法,修改上面的配置类(原因是SpringSecurity认为使用.withUser("ml").password("123456").roles("vip1","vip2")。设置密码太简单,如果使用反编译,密码是极为不方便的。所以将明文加密防止反编译
配置类修改如下

//认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //这些数据正常是从数据库中读出的
        //从内存中认证,也可以从数据库中查询相应角色的数据进行认证
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("ml").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("123")).roles("vip1","vip2","vip3")
                .and()
                .withUser("guest").password(new BCryptPasswordEncoder().encode("12")).roles("vip1");
    }

重启项目,使用下面的账号、密码登陆测试!
在这里插入图片描述
在这里插入图片描述
可以看到使用ml、123456登陆可以访问vip1和vip2下的.antMatchers("/level1/**").hasRole("vip1") .antMatchers("/level2/**").hasRole("vip2")
在这里插入图片描述
在这里插入图片描述但是使用ml、123456登陆却不可以访问 .antMatchers("/level3/**").hasRole("vip3")

4、注销及权限控制

(1)在配置类中的方法protected void configure(HttpSecurity http) throws Exception添加注销功能

//开启注销功能,跳到到首页
        http.logout();

在这里插入图片描述
上面的toLogin是@Controller中请求的路径(请求登陆),而logout不是我们自己写的@Controller中的请求,是根据http.logout点击进去的源码得来的,说明源码中已经给我们定义好了注销功能的路径,不用我们再自己写
在这里插入图片描述
即可使用该密码、账号访问对应的页面!
在这里插入图片描述
点击右上角的“注销”功能!
在这里插入图片描述
点击退出到登陆页面
在这里插入图片描述
当然也可以直接使用我们自己定义好的路由直接退出到首页。修改上面的视图(这个是错误的,上面是正确的的。原因在下面)
在这里插入图片描述
这样即使点击“注销”,但是事实上并没有注销,即使退回到首页,但是我们还可以再次点击访问但是可以不通过账号、密码就可以访问刚才的页面。所以这样的做法是不科学的!所以前面的操作才是正确的
继续正确的操作(注销后再次访问刚才已经访问过的密码必须使用账号、密码),继续修改使

//开启注销功能,跳到到首页
        http.logout().logoutSuccessUrl("/");

这样就可以做到即使注销也可以直接退出到首页,并且保证再次访问与刚才一样的页面也必须是使用账号、密码登陆才可以,保护了数据的安全!这也就是为什么不能使用上面的那种方式,直接在页面添加路由跳转到首页的原因!

(2)、权限控制(根据不同的用户显示不同的版块)

不仅需要security包还需要thymeleafSpringsecurity包进行整合!

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
</dependency>
 <!--thymeleaf和springsecurity整合包-->
<dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>

在index.html页面中添加xmlns:sec="http://www.thymeleaf.org/extras/spring-security"命名空间会出现themleaf和springSecurity的整合代码提示"

<!--登录注销-->
            <div class="right menu">
                <!--如果没有登录只显示登陆没有其他版块-->
                <div sec:authorize="!isAuthenticated()">
                    <a class="item" th:href="@{/toLogin}">
                        <i class="address card icon"></i> 登录
                    </a>
                </div>
                <!--只有登陆才会有用户名-->
                <div sec:authorize="isAuthenticated()">
                    <!--注销-->
                    <a class="item">
                        用户名: <span sec:authentication="name"></span>
                        <!--角色: <span sec:authentication="role"></span>-->
                    </a>
                </div>
                <!--只有登陆才会有注销-->
                <div sec:authorize="isAuthenticated()">
                    <a class="item" th:href="@{/logout}">
                        <i class="sign-out icon"></i> 注销
                    </a>
                </div>
            </div

使用ip http://localhost:8001/登陆首页如下,只有“登陆”字样,没有“用户名和注销”
在这里插入图片描述
随便点击一个,使用对应拥有权限的的密码和账户登陆,我选择auth.inMemoryAuthentication() .withUser("ml").password("123456").roles("vip1","vip2"),登陆如下
在这里插入图片描述

点击登陆之后可以看到有对应的“用户名和注销操作”

在这里插入图片描述
点击“注销操作”之后可以看到没有了对应权限操作的“用户名和注销操作”
在这里插入图片描述
但是以上还存在的问题是在没有任何相应权限的用户登陆的时候,应该在首页什么都不显示;而在登陆之后应该显示其具有权限操作的版块

<div>
        <br>
        <div class="ui three column stackable grid">
            <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>

        </div>
    </div>
<div class="column" sec:authorize="hasRole('vip1')">
<div class="column" sec:authorize="hasRole('vip2')">
<div class="column" sec:authorize="hasRole('vip3')">

这样在没有任何相应权限的用户登陆的时候,应该在首页什么都不显示
在这里插入图片描述
但是使用账号、密码登陆ip http://localhost:8001/login之后可以看见显示具有相应权限的版块! .antMatchers("/").permitAll() .antMatchers("/level1/**").hasRole("vip1") .antMatchers("/level2/**").hasRole("vip2") .antMatchers("/level3/**").hasRole("vip3"); .withUser("ml").password("123456").roles("vip1","vip2") .and() .withUser("root").password("123").roles("vip1","vip2","vip3") .and() .withUser("guest").password("1").roles("vip1");
在这里插入图片描述
这样可以直接点击访问想要的操作!
同理使用 .withUser("root").password("123").roles("vip1","vip2","vip3")登陆可以看见所有权限的版块
在这里插入图片描述

在这里插入图片描述
至此“权限控制操作”到此结束!

5、记住我以及首页定制

(1)、记住我

在配置类中的protected void configure(HttpSecurity http) throws Exception方法中添加

//防止网站工具:get、post
        http.csrf().disable(); //关闭csrf功能,登陆失败可能存在的原因
        http.logout().logoutSuccessUrl("/");
        //开启记住我的功能 cookie,默认保存两天
        http.rememberMe();

使用 http.rememberMe();就开启了记住我功能
在这里插入图片描述
可以与之前的登陆页面比较一下“记住我”功能就有了!
在这里插入图片描述
然后关掉浏览器,再次使用iphttp://localhost:8001/访问,可以发现不用账号、密码可以直接访问之前访问过的页面,这就是记住我的功能的实现!
在这里插入图片描述
可以发现“记住我的功能”是通过cookie实现的,时间是两周
在这里插入图片描述
所以要是清除掉cookie,那么“记住我的功能”就会失效!

(2)、首页定制(登陆页面)因为之前演示的操作都是使用springSecurity中已经写好的登陆页面

在这里插入图片描述
获取角色:principal.authorities
在这里插入图片描述
要使用我们自己定义好的只需要在在配置类中的protected void configure(HttpSecurity http) throws Exception方法中修改

//没有权限默认会到登陆页面,修改springSecurity到我们自己定义好的登陆页面,这样原来springSecurity中定义好的页面就不能使用,失效了
        http.formLogin().loginPage("/toLogin");

在这里插入图片描述
在这里插入图片描述
所以使用我们自己定义好的登陆页面,没有了“记住我的功能”
在这里插入图片描述
但是登陆失败,可以看到路由,我们没有这个请求路径http://localhost:8001/usr/login
在这里插入图片描述
将login.html中的跳转路由修改如下(修改前
在这里插入图片描述
login.html中的跳转路由修改修改后
在这里插入图片描述
再次登陆测试
在这里插入图片描述
成功!
在这里插入图片描述
当然也可以这样修改!login.html中的登陆请求依然使用springSecurity规定的请求路径“/login”,而不是使用上面我们自己定义好的“toLogin”,并且在配置类中的方法 protected void configure(HttpSecurity http) throws Exception中添加修改如下
在这里插入图片描述

//没有权限默认会到登陆页面,修改springSecurity到我们自己定义好的登陆页面,这样原来springSecurity中定义好的页面就不能使用,失效了
        http.formLogin().loginPage("/toLogin").loginProcessingUrl("/login");

这样也可以访问成功!
在这里插入图片描述
这样也会出现各种问题:因为在我们自己定义好的login.html中登陆请求的是 <input type="text" placeholder="Username" name="username"> 和 <input type="password" name="password">,而按照 http.formLogin().loginPage("/toLogin").loginProcessingUrl("/login");虽然走的是“/toLogin”但是还是走的是springSecurity默认的路径参数规定。此时必须保证formLogin中的username、password和前端中的username、password相同,否则还是登陆不了
在这里插入图片描述
在配置类中做出如下修改:

//没有权限默认会到登陆页面,修改springSecurity到我们自己定义好的登陆页面,这样原来springSecurity中定义好的页面就不能使用,失效了
        http.formLogin().usernameParameter("username").passwordParameter("password").loginPage("/toLogin").loginProcessingUrl("/login");

这样即使前端中的name属性中的值和人家底层默认的不一样,我们还是可以在这里修改与前端中的一样保证不出错!
所以两种方式定义首页

第一种

//没有权限默认会到登陆页面,修改springSecurity到我们自己定义好的登陆页面,这样原来springSecurity中定义好的页面就不能使用,失效了
        http.formLogin().loginPage("/toLogin");

index.html页面跳转到登陆页面
在这里插入图片描述
login.html页面登陆
在这里插入图片描述

第二种

//没有权限默认会到登陆页面,修改springSecurity到我们自己定义好的登陆页面,这样原来springSecurity中定义好的页面就不能使用,失效了
        http.formLogin().usernameParameter("username").passwordParameter("password").loginPage("/toLogin").loginProcessingUrl("/login");

在这里插入图片描述
在这里插入图片描述
当然在定制首页中再加一个“记住我的功能”
在这里插入图片描述

 //开启记住我的功能 cookie
        http.rememberMe().rememberMeParameter("remember");

首页定制成功!

6、上面用到的java配置类

package com.ml.springSecurity.config;


import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

//Aop横切的方式
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //授权
        //首页所有的人都可以访问,功能页只有对应有权限的人才可以访问
        //请求授权的规则
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip2")
                .antMatchers("/level3/**").hasRole("vip3");
        //没有权限默认会到登陆页面,修改springSecurity到我们自己定义好的登陆页面,这样原来springSecurity中定义好的页面就不能使用,失效了
        http.formLogin().usernameParameter("username").passwordParameter("password").loginPage("/toLogin").loginProcessingUrl("/login");
        //开启注销功能,跳到到首页
        //防止网站工具:get、post
        http.csrf().disable(); //关闭csrf功能,登陆失败可能存在的原因
        http.logout().logoutSuccessUrl("/");
        //开启记住我的功能 cookie
        http.rememberMe().rememberMeParameter("remember");
    }

    //认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //这些数据正常是从数据库中读出的
        //从内存中认证,也可以从数据库中查询相应角色的数据进行认证
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("ml").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("123")).roles("vip1","vip2","vip3")
                .and()
                .withUser("guest").password(new BCryptPasswordEncoder().encode("12")).roles("vip1");
    }


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Q渡劫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值