SpringBoot——整合SpringSecurity

19 篇文章 0 订阅
8 篇文章 0 订阅

Spring Security是一个框架,侧重于为Java应用程序提供身份验证和授权。与所有Spring项目一样,Spring Security的真正强大之处在于它可以轻松地扩展以满足定制需求

环境准备

  1. 静态资源
    在这里插入图片描述
    素材下载

  2. 编写路由controller

@Controller
public class RouterController {

    @GetMapping({"/", "/index", "/index.html"})
    public String index() {
        return "index";
    }

    @GetMapping({"/toLogin", "/login.html"})
    public String login() {
        return "views/login";
    }

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

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

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

测试环境

Spring Security

要使用spring security只要引入依赖spring-boot-starter-security

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

重要的几个类:

  • WebSecurityConfigurerAdapter:自定义Security策略

  • AuthenticationManagerBuilder:自定义认证策略

  • @EnableWebSecurity:开启WebSecurity模式

Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)

“认证”(Authentication)

身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。

身份验证通常通过用户名和密码完成,有时与身份验证因素结合使用。

“授权” (Authorization)

授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。

这个概念是通用的,而不是只在Spring Security 中存在

认证和授权

  1. 编写spring security配置类
package com.wcy.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;


@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
       
    }
}
  1. 自定义授权
//授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 所有人可以访问首页,但是level页面只有对应权限的人可以访问
        http.authorizeRequests()
                .antMatchers("/", "/index", "/index.html").permitAll()
                .antMatchers("/level1/**").hasAnyRole("v1")
                .antMatchers("/level2/**").hasAnyRole("v2")
                .antMatchers("/level3/**").hasAnyRole("v3");

        // 权限不足跳转到登陆页面
        // /login 请求来到登录页
		// /login?error 重定向到这里表示登录失败
        http.formLogin();
    }
  1. 此时测试会发现除了主页面,点击其他页面都会进入/login页面
    因为权限不足
    在这里插入图片描述
  2. 自定义认证
//认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    // 从内存定义用户,也可以在jdbc中拿
    // 用and()可以连接多个用户
    // 密码必须要加密
    auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
            .withUser("wcy").password(new BCryptPasswordEncoder().encode("123")).roles("v1", "v2", "v3")
            .and()
            .withUser("lqy").password(new BCryptPasswordEncoder().encode("123")).roles("v1", "v2")
            .and()
            .withUser("sep").password(new BCryptPasswordEncoder().encode("123")).roles("v1");
}

此时再去访问,登录后就可以访问对应权限的页面

注销

注销需要在前端添加一个链接/logout

<a class="item" th:href="@{/logout}">
 	<i class="address card icon"></i> 注销
</a>
//授权
@Override
protected void configure(HttpSecurity http) throws Exception {
    // 所有人可以访问首页,但是level页面只有对应权限的人可以访问
    http.authorizeRequests()
            .antMatchers("/", "/index", "/index.html").permitAll()
            .antMatchers("/level1/**").hasAnyRole("v1")
            .antMatchers("/level2/**").hasAnyRole("v2")
            .antMatchers("/level3/**").hasAnyRole("v3");

    // 权限不足跳转到登陆页面
    http.formLogin();

    // 注销及注销后返回的页面
    http.logout().logoutSuccessUrl("/");
}

控制权限

用户没有登录的时候,导航栏上只显示登录按钮,用户登录之后,导航栏可以显示登录的用户信息及注销按钮
还有就是,比如一个用户,它只有 vip2,vip3功能,那么登录则只显示这两个功能的菜单,而vip1的功能菜单不显示!这个就是真实的网站情况了!该如何做呢?

  1. 首先需要结合thymeleaf来实现,导入依赖
<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity5</artifactId>
    <version>3.0.4.RELEASE</version>
</dependency>
  1. 前端页面导入命名空间
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"
  1. 使用sec:authorize="isAuthenticated()":判断是否认证登录!用来显示不同的页面
<!--未登录-->
<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">
        <i class="address card icon"></i>
        用户名:<span sec:authentication="principal.username"></span>&nbsp;&nbsp;
        角色:<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>

测试,现在实现了该功能

如果注销404了,就是因为它默认防止csrf跨站请求伪造,因为会产生安全问题,我们可以将请求改为post表单提交,或者在spring security中关闭csrf功能;我们试试:在 配置中增加 http.csrf().disable();

http.csrf().disable();//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求
http.logout().logoutSuccessUrl("/");

下面继续实现菜单权限控制的功能
使用sec:authorize="hasRole('v1')"来判断是否有v1权限

<div class="column" sec:authorize="hasRole('v1')">
    <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('v2')">
    <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('v3')">
    <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>

此时如果再访问,只能访问对应权限的菜单

记住我

现在的情况,我们只要登录之后,关闭浏览器,再登录,就会让我们重新登录,但是很多网站的情况,就是有一个记住密码的功能,这个该如何实现呢?很简单

1、开启记住我功能

//定制请求的授权规则
@Override
protected void configure(HttpSecurity http) throws Exception {
   //记住我
   http.rememberMe();
}

2、我们再次启动项目测试一下,发现登录页多了一个记住我功能,我们登录之后关闭 浏览器,然后重新打开浏览器访问,发现用户依旧存在
实际就是登录成功后,将cookie发送给浏览器保存,以后登录带上这个cookie,只要通过检查就可以免登录了。如果点击注销,则会删除这个cookie

定制登陆页面

之前权限不足的登陆页面都是框架提供的,那想要使用自己的登陆页面该如何做?

只需要指定到我们自己登陆页面的路由即可

// 权限不足跳转到登陆页面 指定登陆页面
http.formLogin().loginPage("/toLogin");

不过现在登陆会发生404的错误,因为我们使用的是自己的登陆页面,但是我们并没有自己写登陆的逻辑代码,所以还是需要交给框架来做
只需要指定处理的url

// 权限不足跳转到登陆页面 指定登陆页面
http.formLogin().loginPage("/toLogin").loginProcessingUrl("/login");

前端需要路由跳转

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

登陆表单提交到/login

<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>

这个请求提交上来,我们还需要验证处理,怎么做呢?我们可以查看formLogin()方法的源码,我们配置接收登录的用户名和密码的参数
默认情况下,参数的名称就是username和password,如果表单中的名称不是这样,就使用usernameParameter和passwordParameter来指定

http.formLogin()
                .loginPage("/toLogin")
                .loginProcessingUrl("/login")
                .usernameParameter("username")
                .passwordParameter("password");

现在就可以使用自己的登陆页面来实现

在登陆页面中添加记住我功能
首先在form表单中添加

<input type="radio" name="remember">记住我

然后后台处理参数即可

// 记住我
http.rememberMe().rememberMeParameter("remember");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值