导入依赖
<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 利用的是网站对用户网页浏览器的信任。