Spring Security简介;项目中应用Spring Security;自定义登录验证;记忆功能实现;退出登录;Spring Security中CSRF

一,Spring Security简介

        Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

        它是一个认证【身份认证】及授权【权限控制】的框架。shiro是它的对标框架,springsecurity已经开发很多年了,由于shiro的优势,它发展的不是很好,直到springboot出现,security的配置变的非常简单,现在微服务的项目都会优先选择security框架。security实现原理是通过Filter实现的。

二,项目中应用Spring Security

1.启动认证

1.1创建maven项目

        

1.2.添加pom依赖

    <dependencies>
        <!-- SpringBoot -->
       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.1.10.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- SpringMVC -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.1.10.RELEASE</version>
        </dependency>
        <!-- Thymeleaf -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
            <version>2.1.10.RELEASE</version>
        </dependency>
        <!--Spring Security-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>2.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.7.0</version>
        </dependency>
        <!--json-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.60</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

1.3.配置yml端口号

server:
  port: 8181

1.4.编写控制器

@Controller
public class DemoController {
    @RequestMapping("/main")
    public String show(){
        return "main";
    }
}

1.5.编写templates主页面

1.6.编写启动类:

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

1.7.启动项目,访问/main: 自动跳转到:

启动项目,访问项目主页面http://localhost/main,项目会自动跳转到一个登录页面。这代表Spring Security已经开启了认证功能,不登录无法访问所有资源,该页面就是Spring Security自带的登录页面。

完成一下Spring Security 自带的登录功能:

用户名默认:user

密码为 idea控制台输出的内容 :

登录成功后:自动跳转到 刚刚想要访问的页面!

2.自定义认证逻辑

当什么也没有配置的时候,账号和密码是由Spring Security定义生成的。而在实际项目中账号和密码都是从数据库中查询出来的。 所以我们要通过自定义逻辑控制认证逻辑。

如果需要自定义逻辑时,只需要实现UserDetailsService接口即可。接口定义如下:

2.1.编写SecurityConfig 配置类:

package com.jr.config;

@Configuration
public class SecurityConfig {

    @Bean
    public PasswordEncoder getPwdEncoder(){
        return new BCryptPasswordEncoder();//密码加密处理(输入不可见)
    }
}

2.2.编写UserDetailsServiceImpl ,UserDetailsService接口的实现类,用于实现自定义逻辑:

package com.jr.service.serviceImpl;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private PasswordEncoder encoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //1. 查询数据库判断用户名是否存在,如果不存在抛出UsernameNotFoundException
        if(!username.equals("admin")){
            throw new UsernameNotFoundException("用户名不存在");
        }
        //把查询出来的密码进行解析,或直接把password放到构造方法中。
        //理解:password就是数据库中查询出来的密码,查询出来的内容不是123
        String password = encoder.encode("123");
        return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
        //匹配成功后将用户和密码存入User对象,User对象是系统自带的
    }
}

2.3.重启项目

在页面中输入账号:admin,密码:123。后可以正确进入到main.html页面。

3.自定义登录页面

虽然Spring Security给我们提供了登录页面,但是对于实际项目中,大多喜欢使用自己的登录页面。所以Spring Security中不仅仅提供了登录页面,还支持用户自定义登录页面。实现过程也比较简单,只需要修改配置类即可。

3.1.编写login.html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>内容</title>
</head>
<body>
<form action="/login" method="post">
    <input type="text" name="username"/>
    <input type="password" name="password"/>
    <input type="submit" value="提交"/>
</form>

</body>
</html>

3.2.修改配置类:

修改配置类中主要是设置哪个页面是登录页面。配置类需要继承WebSecurityConfigurerAdapter,并重写configure方法。

successForwardUrl()登录成功后跳转地址

loginPage() 登录页面

loginProcessingUrl 登录页面表单提交地址,此地址可以不真实存在。

antMatchers():匹配内容

permitAll():允许

package com.jr.config;

@Configuration
public class SecurityConfig  extends WebSecurityConfigurerAdapter {

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

        // 表单认证
        http.formLogin()
                .loginProcessingUrl("/login") 
                //此处表单不写action属性也可以  //当发现/login时认为是登录,需要执行UserDetailsServiceImpl
                .successForwardUrl("/main")   //此处是post请求
                .loginPage("/login.html");

        // url 拦截
        http.authorizeRequests()
                .antMatchers("/login.html").permitAll() //login.html不需要被认证
                .anyRequest().authenticated();//所有的请求都必须被认证。必须登录后才能访问。

        //关闭csrf防护
        http.csrf().disable();

    }

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

4.记忆(Remember Me) 功能实现

4.1.添加依赖:

  <!-- 4.添加mysql数据库的驱动包依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>
        <!-- 3.添加Mybatis 的启动器依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>

4.2.修改配置文件,添加连接数据库四要素

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/security

4.3.添加配置文件:

package com.jr.config;

@Configuration
public class RememberMeConfig {

    @Autowired
    private DataSource dataSource;
    @Bean
    public PersistentTokenRepository getPersistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepositoryImpl=new JdbcTokenRepositoryImpl();
        jdbcTokenRepositoryImpl.setDataSource(dataSource);
        //自动建表,第一次启动时需要,第二次启动时注释掉
        //jdbcTokenRepositoryImpl.setCreateTableOnStartup(true);  //该代码不好用,使用sql手动创建库,表
        return jdbcTokenRepositoryImpl;
    }
    
}

4.4.修改 SecurityConfig 配置文件:

  @Autowired
    PersistentTokenRepository repository;
   // private  RememberMeConfig repository;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;
    
    
    http.rememberMe()
        .userDetailsService(userDetailsService) //登录逻辑交给哪个对象
        .tokenRepository(repository);   //持久层对象

4.5.修改登录页面:

   <input type="checkbox" name="remember-me" value="true"/> <br/>

4.6.创建数据库 security ,创建数据库表persistent_logins语句:

create table persistent_logins (
username varchar(64) not null, 
series varchar(64) primary key, 
token varchar(64) not null, 
last_used timestamp not null)

【说明:重启服务器之后,仍然可以记住你!访问/main,可以直接跳转到main页面,不会再要求登录了。】

5.Thymeleaf中Spring Security的使用

5.1.获得属性

可以在html页面中通过 sec:authentication=""获取UsernamePasswordAuthenticationToken中所有getXXX的内容,包含父类中的getXXX的内容。

根据源码得出下面属性:

name:登录账号名称

principal:登录主体,在自定义登录逻辑中是UserDetails

credentials:凭证(密码)

authorities:权限和角色

details:实际上是WebAuthenticationDetails的实例。可以获取remoteAddress(客户端ip)和sessionId(当前sessionId)

1.添加依赖:

   <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
            <version>3.0.4.RELEASE</version>
        </dependency>

2.创建页面:

在项目resources中新建templates文件夹,在templates中新建demo.html页面

<!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">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
登录账号:<span sec:authentication="name">123</span><br/>
登录账号:<span sec:authentication="principal.username">456</span><br/>
凭证:<span sec:authentication="credentials">456</span><br/>
权限和角色:<span sec:authentication="authorities">456</span><br/>
客户端地址:<span sec:authentication="details.remoteAddress">456</span><br/>
sessionId:<span sec:authentication="details.sessionId">456</span><br/>
</body>
</html>

3.编写控制器:

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

5.2.权限判断

在html页面中可以使用sec:authorize=”表达式”进行权限控制,判断是否显示某些内容。表达式的内容和access(表达式)的用法相同。如果用户具有指定的权限,则显示对应的内容;如果表达式不成立,则不显示对应的元素。

1.设置用户角色和权限

设定用户具有admin,/insert,/delete权限ROLE_abc角色。

  return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_abc,/insert,/delete"));

2.修改demo页面,展示效果:

<!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">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
登录账号:<span sec:authentication="name">123</span><br/>
登录账号:<span sec:authentication="principal.username">456</span><br/>
凭证:<span sec:authentication="credentials">456</span><br/>
权限和角色:<span sec:authentication="authorities">456</span><br/>
客户端地址:<span sec:authentication="details.remoteAddress">456</span><br/>
sessionId:<span sec:authentication="details.sessionId">456</span><br/>

通过权限判断:
<button sec:authorize="hasAuthority('/insert')">新增</button>
<button sec:authorize="hasAuthority('/delete')">删除</button>
<button sec:authorize="hasAuthority('/update')">修改</button>
<button sec:authorize="hasAuthority('/select')">查看</button>
<br/>
通过角色判断:
<button sec:authorize="hasRole('abc')">新增</button>
<button sec:authorize="hasRole('abc')">删除</button>
<button sec:authorize="hasRole('abc')">修改</button>
<button sec:authorize="hasRole('abc1')">查看</button>
</body>
</html>

6.退出登录

用户只需要向Spring Security项目中发送/logout退出请求即可。

1.修改demo页面:

<a href="/logout">退出登录</a>

7.Spring Security中CSRF

从刚开始学习Spring Security时,在配置类中一直存在这样一行代码:http.csrf().disable();如果没有这行代码导致用户无法被认证。这行代码的含义是:关闭csrf防护。

7.1什么是CSRF

CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack” 或者Session Riding。通过伪造用户请求 访问受信任站点的非法请求访问。

跨域:只要网络协议,ip地址,端口中任何一个不相同就是跨域请求。

客户端与服务进行交互时,由于http协议本身是无状态协议,所以引入了cookie进行记录客户端身份。在cookie中会存放session id用来识别客户端身份的。在跨域的情况下,session id可能被第三方恶意劫持,通过这个session id向服务端发起请求时,服务端会认为这个请求是合法的,可能发生很多意想不到的事情。

7.2Spring Security中CSRF

从Spring Security4开始CSRF防护默认开启。默认会拦截请求。进行CSRF处理。CSRF为了保证不是其他第三方网站访问,要求访问时携带参数名为_csrf值为token(token在服务端产生)的内容,如果token和服务端的token匹配成功,则正常访问。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值