SpringBoot整合security

springboot整合security

参考:
1.什么是token
https://www.jianshu.com/p/24825a2683e6

2.SpringBoot安全管理–(一)SpringSecurity基本配置
https://www.cnblogs.com/crazy-lc/p/12361118.html

3.BCrypt 密码加密和解密
https://www.jianshu.com/p/fc910a1f7c8d/

4.springboot 的安全管理
https://blog.csdn.net/daqi1983/article/details/115508248

1.添加依赖

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

2.添加接口

@RestController
public class HelloController {

//    3.进行身份认证
    @GetMapping("/hello")
    public String hello() {
        return "hello codeL!";
    }

}

3.启动项目会方向所有路径都被拦截下来了,需要登录才能进入

在这里插入图片描述
密码在idea的控制台上会显示出来,这是内部写好的,可以通过配置类去修改,下面有三种方法去修改。

Security包

需要修改Security配置就需要在Security包里面对一些类进行重写。

项目引入spring-boot-starter-security依赖启动器,MVC Security安全管理功能就会自动生效,其默认的安全配置是在SecurityAutoConfiguration和UserDetailsServiceAutoConfiguration中实现的。所以修改里面的配置可以得到我们自己想要的结果。

SecurityAutoConfiguration导入并自动化配置SpringBootWebSecurityConfiguration用于启动Web安全管理.

UserDetailsServiceAutoConfiguration用于配置用户身份信息.
在这里插入图片描述
可以通过自定义WebSecurityConfigurerAdapter类型的Bean组件来覆盖默认访问规则。在这里插入图片描述

configure(HttpSecurity http):自定义用户授权管理 控制http的访问路径
configure(AuthenticationManagerBuilder auth) :身份验证管理器生成器 控制登陆身份
在这里插入图片描述

1.内存身份认证


/*
 @EnableWebSecurity注解是一个组合注解,
 主要包括@Configuration注解、
 @Import({WebSecurityConfiguration.class, SpringWebMvcImportSelector.class})注解
 和@EnableGlobalAuthentication注解
*/
//网络安全配置适配器
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private DataSource dataSource;
    @Autowired
    private UserDetailServiceImpl userDetailService;

    //自定义用户认证
    @Override
//    身份验证管理器生成器  3.使用jdbc进行身份认证
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        B Crypt 密码编码器
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

   //  1. 使用内存身份进行认证(测试)

     //   ===================================

        auth.inMemoryAuthentication().passwordEncoder(encoder).withUser("codeLL").password(encoder.encode("123456")).roles("common").and()
                .withUser("chen").password(encoder.encode("123")).roles("Vip");
    
}

2.基于jdbc身份认证

//2.  使用jdbc进行身份认证(开发)

        String userSQL = "select username,password,valid from t_customer " + "where username = ?";

        String authoritySQL = "select c.username,a.authority from t_customer c, " + "t_authority a,t_customer_authority ca where " + "ca.customer_id=c.id and ca.authority_id=a.id and c.username =?";

        auth.jdbcAuthentication().passwordEncoder(encoder).dataSource(dataSource).usersByUsernameQuery(userSQL).authoritiesByUsernameQuery(authoritySQL);


各个表之间的关系
在这里插入图片描述
测试之前,先把数据库配置信息,驱动包对应的依赖导进去

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-jdbc</artifactId>

</dependency>

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

<scope>runtime</scope>

</dependency>

application.yaml

spring:
  datasource:
    username: root
    password: abcde
    url: jdbc:mysql://localhost:3306/springbootdata?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver

然后开启登录,根据数据库的信息进行登录。测试之前要把redis里面之前测试的数据缓存删除掉,不然会报序列化的错误。

3.UserDetailsService 身份认证

//3.userDetailService身份认证    这个可以直接使用service里面配置的
//        userDetailService里面含有对象的详细信息
        auth.userDetailsService(userDetailService).passwordEncoder(encoder);

逻辑图:
在这里插入图片描述

4.自定义用户授权管理

 //    2.自定义用户授权管理   Http安全
    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        路径“/"直接放行
        http.authorizeRequests().antMatchers("/").permitAll()
        // permitAll表示和登陆相关的接口不需要认证
//                放行“common  表示访问/common/**路径的必须要admin角色,后面两个也一样道理。
                .antMatchers("/common/**").hasRole("common")
//                放行vip
                .antMatchers("/vip/**").hasRole("vip")
//                登录的才能放行

                .anyRequest().authenticated()//表示除了前面定义的url,后面的都得认证后访问(登陆后访问)
                .and().formLogin();// permitAll表示和登陆相关的接口不需要认证

//        注销
        http.logout().logoutUrl("/mylogout").logoutSuccessUrl("/");

//        经过测试,拦截成功
    }

controller类


/**
 * 文件控制器
 *
 * @author codel
 * @date 2021/09/12
 */
@Controller
public class FileController {
    /**
     *  定义进入详细影片的api
     *
     * @param type 类型
     * @param path 路径
     * @return {@link String}
     */
    @GetMapping("/{type}/{path}")
    public String toDetail(@PathVariable("type") String type, @PathVariable("path") String path) {
        return type + "/" + path;
    }
}

配置视图:
在这里插入图片描述
会发现,没vip的权限不能进入vip的页面。

5.自定义用户退出

<form th:action="@{/mylogout}" method="post">

        <label>
            <input th:type="submit" th:value="注销" style="color: blue"/>
        </label>

    </form>

在SecurityConfig类,重写configure(HttpSecurity http)方法进行用户退出控制,在该方法中添加如下代码

  //  2. 注销
        http.logout().logoutUrl("/mylogout").logoutSuccessUrl("/");

6.获取登录用户信息

使用SecurityContextHolder获取用户信息

/**
     * 通过Security提供的SecurityContextHolder获取登录用户信息
     */
    @GetMapping("/getuserByContext")
    @ResponseBody
    public List<Object> getUser2() {
        List<Object> list = new ArrayList<>();
        // 获取应用上下文
        SecurityContext context = SecurityContextHolder.getContext();
        System.out.println("userDetails: " + context);

        // 获取用户相关信息
        Authentication authentication = context.getAuthentication();
        UserDetails principal = (UserDetails) authentication.getPrincipal();
        System.out.println(principal);
        System.out.println("username: " + principal.getUsername());
        list.add(context);
        list.add(principal);
        list.add(principal.getUsername());
        return list;
    }

用户信息:
在这里插入图片描述

7.记住我功能实现

记住时长:登录之后,注销之前或token失效之前

基于持久化Token方式

建立Token表
在这里插入图片描述

更新 configure(HttpSecurity http)配置:


        //   3.配置记住我的功能
        http.rememberMe().rememberMeParameter("rememberme").tokenValiditySeconds(200)
//        点击记住我,然后重启浏览器,发现不用输入密码和账号,直接进入首页
                // 注意:这里是对cookie信息进行持久化管理,也可以使用简单加密的方式
                .tokenRepository(tokenRepository());
//        经过测试,拦截成功

//        设置关闭CSRF功能
//        http.csrf().disable();
    }

    /**
     * 持久化Token存储
     */
    @Bean
    public JdbcTokenRepositoryImpl tokenRepository() {
//        Jdbc 令牌存储库实现
        JdbcTokenRepositoryImpl jr = new JdbcTokenRepositoryImpl();
        jr.setDataSource(dataSource);
        return jr;

    }

了解token
在这里插入图片描述
在这里插入图片描述
重启项目进行效果测试,通过浏览器访问项目首页,输入正确的账户信息,

勾选记住我后,跳转到项目首页index.html,
数据库的变化

在这里插入图片描述

注销后,数据库数据没有了。
在这里插入图片描述

8.CSRF防护功能

也就是防止而已恶意增删改数据

html页面

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" lang="en">

<head>
    <meta charset="UTF-8">
    <title>用户修改</title>
</head>
<body>
<div align="center">
    <!--    这种是thymeleaf模板方式配置属性请求,会默认携带CSRF Token的信息-->
    <!--    <form method="post" th:action="@{/updateUser}">-->

    <!--    这是显性的配置CSRF token的方式进行获取用户验证信息-->
    <form method="post" action="/updateUser">
        <input type="hidden" th:name="${_csrf.getParameterName()}" th:value="${_csrf.token}">
        <!--        这是显示的方式,没有关闭默认的CSRF配置是不能进行增删改的-->
        <!--    <form method="post" action="/updateUser">-->
        用户名: <label>
        <input type="text" name="username"/>
    </label><br/>
        密 码: <label>
        <input type="password" name="password"/>
    </label><br/>
        <button type="submit">修改</button>
    </form>
</div>
</body>
</html>
package com.codel.securitylogin.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;

/**
 * csrfcontroller
 *
 * @author codel
 * @date 2021/09/12
 */
@Controller
public class CSRFController {

    // 向用户修改页跳转
    @GetMapping("/toUpdate")
    public String toUpdate() {
        return "csrf/csrf";
    }

    // 用户修改提交处理
    @ResponseBody
    @PostMapping(value = "/updateUser")
    public String updateUser(@RequestParam String username, @RequestParam String password, HttpServletRequest request) {
        System.out.println(username);
        System.out.println(password);
        String csrf_token = request.getParameter("_csrf");
        System.out.println(csrf_token);
        return "ok";
    }

}

测试,没有关闭csrf会显示报错,因为security默认开启csrf

//        设置关闭CSRF功能
  http.csrf().disable();

关闭后就可以修改成功了。

但是这样不安全,所以要使用CSRF Token方式来配置

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" lang="en">

<head>
    <meta charset="UTF-8">
    <title>用户修改</title>
</head>
<body>
<div align="center">
    <!--    这种是thymeleaf模板方式配置属性请求,会默认携带CSRF Token的信息-->
    <!--    <form method="post" th:action="@{/updateUser}">-->

    <!--    这是显性的配置CSRF token的方式进行获取用户验证信息-->
    <form method="post" action="/updateUser">
        <input type="hidden" th:name="${_csrf.getParameterName()}" th:value="${_csrf.token}">
        <!--        这是显示的方式,没有关闭默认的CSRF配置是不能进行增删改的-->
        <!--    <form method="post" action="/updateUser">-->
        用户名: <label>
        <input type="text" name="username"/>
    </label><br/>
        密 码: <label>
        <input type="password" name="password"/>
    </label><br/>
        <button type="submit">修改</button>
    </form>
</div>
</body>
</html>

使用Thymeleaf模板会默认带着token的,所以可以提交数据修改。

9.前端页面管理

1.添加thymeleaf-extras-springsecurity5依赖启动器
  <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </dependency>
2.修改前端页面,使用Security相关标签进行页面控制

在index.html页面中引入Security安全标签

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"

       xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">

修改后的index页面

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5" lang="en">

<!--页面顶部通过“xmlns:sec”引入了Security安全标签,页面中根据需要编写了4个-->
<!--<div>模块.-->
<body>
<div sec:authorize="isAnonymous()">

    <h2 align="center">游客您好,如果想查看电影<a th:href="@{/userLogin}">请登录</a></h2></div>

<div sec:authorize="isAuthenticated()">

    <h2 align="center"><span sec:authentication="name" style="color: #007bff"></span>

        您好,您的用户权限为<span sec:authentication="principal.authorities" style="color:darkkhaki"></span>,您有权观看以下电影</h2>

    <form th:action="@{/mylogout}" method="post">

        <label>
            <input th:type="submit" th:value="注销" style="color: blue"/>
        </label>

    </form>

</div>

<div sec:authorize="hasRole('common')">

    <h3>普通电影</h3>

    <ul>
        <li><a th:href="@{/common/1}">我不是药神</a></li>

        <li><a th:href="@{/common/2}">夏洛特烦恼</a></li>
    </ul>

</div>

<div sec:authorize="hasAuthority('ROLE_vip')">

    <h3>VIP专享</h3>

    <ul>
        <li><a th:href="@{/vip/1}">速度与激情</a></li>

        <li><a th:href="@{/vip/2}">猩球崛起</a></li>
    </ul>

</div>
</body>
</html>
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值