SpringBoot-Security

199 阅读3分钟

导入依赖

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

路由控制

@Controller
public class RouterController {
    @GetMapping("/index")
    public String index(){
        return "index";
    }
    @RequestMapping("/toLogin")
    public String login(){
        return "login";
    }
    @RequestMapping("/level1/{id}")
    public String Level1(@PathVariable("id") int id){
        return "level1/"+id;
    }
    @RequestMapping("/level2/{id}")
    public String Level2(@PathVariable("id") int id){
        return "level2/"+id;
    }
    @RequestMapping("/level3/{id}")
    public String Level3(@PathVariable("id") int id){
        return "level3/"+id;
    }
}

用户认证

通过继承WebSecurityConfigurerAdapter和使用@EnableWebSecurity来开启security

package com.demo.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;
import org.springframework.security.crypto.password.PasswordEncoder;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //授权
        //请求规则,首页所有人可访,功能页部分可访
        http.authorizeRequests().antMatchers("/").permitAll()
        //vip1可以访问/level1/** 下的所有
                .antMatchers("/level1/**").hasAnyRole("vip1")
                .antMatchers("/level2/**").hasAnyRole("vip2")
                .antMatchers("/level3/**").hasAnyRole("vip3");
        //当用户没有权限时自动跳到登录页面,有security提供该页面
        http.formLogin();
        
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //授权对象lin有vip1,vip2的权限
        auth.inMemoryAuthentication().
                .withUser("lin").password("123456").roles("vip1","vip2")
                .and()
                .withUser("admin").password("123456").roles("vip1","vip2","vip3")
                .and()
                .withUser("guest").password("123456").roles("vip1");
    }
}

此时会报there is no Passwordencoder mapped 因此需要给授权对象加上编码

 @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("lin").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
                .and()
                .withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
                .and()
                .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
    }

注销

在原本的configure(HttpSecurity http)中添加http.logout().logoutSuccessUrl("/");

http.logout()开启注销,logoutSuccessUrl("/")设置注销成功后跳转的地址

@Override
    protected void configure(HttpSecurity http) throws Exception {
        //授权
        //请求规则,首页所有人可访,功能页部分可访
        http.authorizeRequests().antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasAnyRole("vip1")
                .antMatchers("/level2/**").hasAnyRole("vip2")
                .antMatchers("/level3/**").hasAnyRole("vip3");
        http.formLogin();
        http.logout().logoutSuccessUrl("/");
        //http.httpBasic();
    }

为了让不同权限的用户看见不同的页面部分

导入依赖

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

设置命名空间

<html lang="en" xmlns:sec="http://www.thymeleaf.org/extras/spring-security"  >

修改原本显示登录和注销的部分,使得登录的用户能看见注销按钮,未登录的用户能看见登录按钮

IsAuthenticated属性是一个布尔值,指示当前用户是否已通过身份验证(已登录)。

如果当前用户已通过身份验证,则该属性值是一个布尔值 true,否则是 false。

<!--//未登录-->
<div sec:authorize="!isAuthenticated()">
<a href="/toLogin">登录</a>
</div>
<!--//登录-->
<div sec:authorize="isAuthenticated()">
<a href="/logout">注销</a>
    <a class="item">
        用户名:<span sec:authentication="name"></span> <!--获取用户名-->
        角色:<span sec:authentication="authorities"></span>
    </a>
</div>

同理修改原本显示页面的部分 `

注意:hasRole在进行权限判断时会被追加前缀ROLE_。`

<!DOCTYPE html>
<html lang="en" xmlns:sec="http://www.thymeleaf.org/extras/spring-security"  >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--//未登录-->
<div sec:authorize="!isAuthenticated()">
<a href="/toLogin">登录</a>
</div>
<!--//登录-->
<div sec:authorize="isAuthenticated()">
<a href="/logout">注销</a>
    <a class="item">
        用户名:<span sec:authentication="name"></span>
        角色:<span sec:authentication="authorities"></span>
    </a>
</div>
<div sec:authorize="hasRole('vip1')">
    <a href="level1/1">level1-1</a><br>
    <a href="level1/2">level1-2</a><br>
    <a href="level1/3">level1-3</a><br>
</div>

<div sec:authorize="hasRole('vip2')">
<a href="level2/1">level2-1</a><br>
<a href="level2/2">level2-2</a><br>
    <a href="level2/3">level2-3</a><br>
</div>
<div sec:authorize="hasRole('vip3')">
<a href="level3/1">level3-1</a><br>
<a href="level3/2">level3-2</a><br>
<a href="level3/3">level3-3</a><br>
</div>
</body>
</html>

Remember me 记住我

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
     
        //开启记住我功能,使用cookie存放,
        //rememberMeParameter设置用于激活remember me功能的参数name,默认remember-me
        http.rememberMe().rememberMeParameter("remember-me");
    }
}

前端页面

<form action="/a" method="post">
    用户名:<input type="text" name="name">
    <br>密码:<input type="password" name="pwd">
    <br><input type="checkbox" name="remember-me">remember me
    <input type="submit">
</form>

首页定制

注:测试时发现进行处理认证时报403错误,其原因Spring Security默认开启了csrf 保护

而我们的表单缺少token被禁止访问

(引自网络 www.cnblogs.com/it-deepinmi… blog.csdn.net/csdnluolq/a… )

可根据spring文件加上相应token或 http.csrf().disable();关闭csrf


@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        //开启记住我功能,cookie,设置用于激活remember me功能的参数name,默认remember-me
        http.rememberMe().rememberMeParameter("remember-me");
        //loginPage 设置登录页的url,用户未登录时,访问任何资源都转跳到该路径
        http.formLogin().loginPage("/toLogin").
                //登录表单form中用户名输入框input的name名,不修改的话默认是username
                usernameParameter("name").
                //form中密码输入框input的name名,不修改的话默认是password
                passwordParameter("pwd").
                //登录表单form中action的地址,也就是处理认证请求的路径
                loginProcessingUrl("/a").
                //登录认证成功后默认转跳的路径
                defaultSuccessUrl("/");
    }
}

随笔:CSRF

HttpSecurity http

http.csrf().disable();关闭csrf

跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。