一 、环境搭建
- 搭建简单SpringBoot项目
- 在templates下面搭建简单页面
1.1 pom.xml文件
<properties>
<java.version>1.8</java.version>
<junit.version>4.12</junit.version>
<lombok.version>1.18.12</lombok.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<!-- 数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<!-- 热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- http请求工具包依赖-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
</dependencies>
1.2 application.yml文件配置
server:
port: 8010 #端口号
#spring
# 环境设置:dev、test、prod
spring:
application:
name: sprin-boot-demolhh
profiles:
active: dev
logging:
config: classpath:logback-spring.xml
1.3 基础页面-我随意搭建的没有css样式吼,有强迫症的兄弟姐妹可以自己搭建美观的页面
lhh1.html,一次类推lhh2.html,lhh3.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>lhh1</title>
</head>
<body>
<hr/>
<h1>lhh1-欢欢的测试</h1>
<hr/>
</body>
</html>
index.html 用来跳转页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:sec="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>首页index</title>
</head>
<body>
<div>
<a th:href="@{/login}">
<i>登录</i>
</a>
</div>
<hr/>
<h1>我是首页啊</h1>
<hr/>
<div style="display: block">
<div sec:authorize="hasRole('vip1')">
<a th:href="@{/router/lhh1/1}">
<b>进入lhh1</b>
</a>
</div>
<div>
<a th:href="@{/router/lhh2/2}">
<b>进入lhh2</b>
</a>
</div>
<div>
<a th:href="@{/router/lhh3/3}">
<b>进入lhh3</b>
</a>
</div>
</div>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>我是登录</title>
</head>
<body>
<hr/>
<h1>我是登录</h1>
<hr/>
<form th:action="@{/login}" method="post">
<div><i>用户名</i><input type="text" name="name" placeholder="请输入用户名"/></div>
<div><i>密码</i><input type="password" name="pwd"/></div>
<input type="checkbox" name="remeberme"/>记住密码
<div><input type="submit"/></div>
</form>
</body>
</html>
二、整合SpringSecurity首先导入依赖,进行配置
2.1 pom文件
<!-- thymeleaf模板-->
<!-- https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf-spring5 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-java8time -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
<version>3.0.4.RELEASE</version>
<!--这里一定要写这个版本,即使dependencies显示的有-->
</dependency>
<!-- spring安全security-->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2.2 yml文件
2.3 编写Controll文件
package com.lhh.demolhh.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/router")
public class RouterController {
// 进入 / index 都是进入首页
@RequestMapping({"/","/index"})
public String index1(){
return "index";
}
@RequestMapping("/toLogin")
public String toLogin(){
return "login";
}
@RequestMapping("/lhh1/{id}")
public String index1(@PathVariable("id")int id){
return "lhh1/lhh"+id;
}
@RequestMapping("/lhh2/{id}")
public String index2(@PathVariable("id")int id){
return "lhh2/lhh"+id;
}
@RequestMapping("/lhh3/{id}")
public String index3(@PathVariable("id")int id){
return "lhh3/lhh"+id;
}
}
2.4 编写SecurityConfig.java文件,继承WebSecurityConfigurerAdapter
package com.lhh.demolhh.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;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// 授权
@Override
protected void configure(HttpSecurity http) throws Exception {
//首页所有人可以访问,功能页之恶能对应有权限的人才可访问
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/router/index").permitAll()
.antMatchers("/router/lhh1/**").hasRole("vip1")
.antMatchers("/router/lhh2/**").hasRole("vip2")
.antMatchers("/router/lhh3/**").hasRole("vip3");
}
}
2.5 运行文件
2.5.1 localhost:8010 进入首页
2.5.2 localhost:8010/lhh1/1 ,不能进入页面,报403功能
2.6 从上可以看到没有权限,进入不了页面,这里设置没有权限就跳转登录页面,并设置几个账户,分配角色
package com.lhh.demolhh.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;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// 授权
@Override
protected void configure(HttpSecurity http) throws Exception {
//首页所有人可以访问,功能页之恶能对应有权限的人才可访问
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/router/index").permitAll()
.antMatchers("/router/lhh1/**").hasRole("vip1")
.antMatchers("/router/lhh2/**").hasRole("vip2")
.antMatchers("/router/lhh3/**").hasRole("vip3");
//没有权限默认跳至登录页面,需开启登录界面
http.formLogin();
}
//认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("lhh1").password("123456").roles("vip1")
.and()
.withUser("lhh2").password("123456").roles("vip1","vip2")
.and()
.withUser("lhh3").password("123456").roles("vip1","vip2","vip3");
}
}
2.6.1 再运行,就会进入到security自带的登录界面
2.6.2 进行登录时,报错信息如下
Java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id “null”
解决方式:springboot里面有多种加密方式,这里用BCryptPasswordEncoder.encode(),加密
//认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("lhh1").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1")
.and()
.withUser("lhh2").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
.and()
.withUser("lhh3").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3");
}
三、注销功能
//开启注销功能
/*
.deleteCookies("remove") -->移除Cookie所有
.invalidateHttpSession(true) ---> 清空所有Session
.logoutUrl("/custom-logout") ---> 在哪个地方注销
.logoutSuccessUrl("/logout-success"); --->注销成功后跳转的页面
*/
http.logout().logoutSuccessUrl("/");
四、调整页面,如果没有登录,显示登录。登录过了,显示用户名与角色以及注销
//防止网站工具 get post
http.csrf().disable(); //关闭csrf功能(跨站请求伪造)这可能是登录失败的原因
<div sec:authorize="!isAuthenticated()">
<a th:href="@{router/toLogin}">
<i>登录</i>
</a>
</div>
<div sec:authorize="isAuthenticated()">
<a class="item">
<i class="address card icon"></i>
用户名:<span sec:authentication="name"></span>
角色:<span sec:authentication="principal.authorities"></span>
</a>
<a th:href="@{/logout}">
<i>注销</i>
</a>
</div>
如果代码正确,页面不能正常显示,登录与注销功能不能按条件正确显示
Pom.xml
需要把SpringBoot 的版本调整到 2.1.X 以下
2.0.9即可 不过登录页非常1老旧
据说一般 2.0.7 最稳定
版本修改-》 springsecurity4 换成 springsecurity5
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
thymeleaf-extras-springsecurity版本3.0.4.RELEASE -适用于Thymeleaf 3.0(需要Thymeleaf 3.0.10+) 这里的version自己查一下,改成3.x.x几
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
</dependency>
五、登陆页面
5.1 记住我-功能
http.rememberMe();
5.2 将登陆页面用自己的页面方式
方式一
配置文件里面,配置登录跳转的页面,不用security自带的页面
//没有权限默认跳至登录页面,需开启登录界面
http.formLogin().loginPage("/router/toLogin");
方式二
form表单跳转为login界面,这是配置文件
http.formLogin().loginPage("/router/toLogin").loginProcessingUrl("/login");
其中,如果name 不是username与password,点击登录会路由会跳到 /error 页面,此时可以在配置文件
//没有权限默认跳至登录页面,需开启登录界面
http.formLogin().loginPage("/router/toLogin").usernameParameter("name").passwordParameter("pwd").loginProcessingUrl("login");
5.3 自己登陆页面,添加“记住我”功能
<input type="checkbox"name="remeberme"/>记住密码
配置文件
配置文件
//记住我-功能,cookie默认保存两周,自定义接收前端的参数
http.rememberMe().rememberMeParameter("remeberme");
六、最终代码
6.1 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lhh</groupId>
<artifactId>demolhh</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demolhh</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<junit.version>4.12</junit.version>
<lombok.version>1.18.12</lombok.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<!-- 数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<!-- 热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- http请求工具包依赖-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
<!-- 微信解密工具类-->
<!-- <dependency>-->
<!-- <groupId>org.bouncycastle</groupId>-->
<!-- <artifactId>bcprov-jdk15on</artifactId>-->
<!-- <version>1.59</version>-->
<!-- </dependency>-->
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.64</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.pulsar/pulsar-client-messagecrypto-bc -->
<dependency>
<groupId>org.apache.pulsar</groupId>
<artifactId>pulsar-client-messagecrypto-bc</artifactId>
<version>2.6.0</version>
</dependency>
<!-- thymeleaf模板-->
<!-- https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf-spring5 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-java8time -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
<version>3.0.4.RELEASE</version>
<!--这里一定要写这个版本,即使dependencies显示的有-->
</dependency>
<!-- spring安全security-->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
6.2 login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>我是登录</title>
</head>
<body>
<hr/>
<h1>我是登录</h1>
<hr/>
<form th:action="@{/login}" method="post">
<div><i>用户名</i><input type="text" name="name" placeholder="请输入用户名"/></div>
<div><i>密码</i><input type="password" name="pwd"/></div>
<input type="checkbox" name="remeberme"/>记住密码
<div><input type="submit"/></div>
</form>
</body>
</html>
6.3 index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:sec="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>首页index</title>
</head>
<body>
<div sec:authorize="!isAuthenticated()">
<a th:href="@{router/toLogin}">
<i>登录</i>
</a>
</div>
<div sec:authorize="isAuthenticated()">
<a class="item">
<i class="address card icon"></i>
用户名:<span sec:authentication="name"></span>
角色:<span sec:authentication="principal.authorities"></span>
</a>
<a th:href="@{/logout}">
<i>注销</i>
</a>
</div>
<hr/>
<h1>我是首页啊</h1>
<hr/>
<div style="display: block">
<div sec:authorize="hasRole('vip1')">
<a th:href="@{/router/lhh1/1}">
<b>进入lhh1</b>
</a>
</div>
<div>
<a th:href="@{/router/lhh2/2}">
<b>进入lhh2</b>
</a>
</div>
<div>
<a th:href="@{/router/lhh3/3}">
<b>进入lhh3</b>
</a>
</div>
</div>
</body>
</html>
6.4 lhh1.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>lhh1</title>
</head>
<body>
<hr/>
<h1>lhh1-欢欢的测试</h1>
<hr/>
</body>
</html>
6.5 RouterController.java
package com.lhh.demolhh.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/router")
public class RouterController {
// 进入 / index 都是进入首页
@RequestMapping({"/","/index"})
public String index1(){
return "index";
}
@RequestMapping("/toLogin")
public String toLogin(){
return "login";
}
@RequestMapping("/lhh1/{id}")
public String index1(@PathVariable("id")int id){
return "lhh1/lhh"+id;
}
@RequestMapping("/lhh2/{id}")
public String index2(@PathVariable("id")int id){
return "lhh2/lhh"+id;
}
@RequestMapping("/lhh3/{id}")
public String index3(@PathVariable("id")int id){
return "lhh3/lhh"+id;
}
}
6.5 SecurityConfig.java
package com.lhh.demolhh.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;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// 授权
@Override
protected void configure(HttpSecurity http) throws Exception {
//首页所有人可以访问,功能页之恶能对应有权限的人才可访问
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/router/index").permitAll()
.antMatchers("/router/lhh1/**").hasRole("vip1")
.antMatchers("/router/lhh2/**").hasRole("vip2")
.antMatchers("/router/lhh3/**").hasRole("vip3");
//没有权限默认跳至登录页面,需开启登录界面
http.formLogin().loginPage("/router/toLogin").usernameParameter("name").passwordParameter("pwd").loginProcessingUrl("/login");
//防止网站工具 get post
http.csrf().disable(); //关闭csrf功能(跨站请求伪造)这可能是登录失败的原因
//开启注销功能
/*
.deleteCookies("remove") -->移除Cookie所有
.invalidateHttpSession(true) ---> 清空所有Session
.logoutUrl("/custom-logout") ---> 在哪个地方注销
.logoutSuccessUrl("/logout-success"); --->注销成功后跳转的页面
*/
http.logout().logoutSuccessUrl("/");
//记住我-功能,cookie默认保存两周,自定义接收前端的参数
http.rememberMe().rememberMeParameter("remeberme");
}
//认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("lhh1").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1")
.and()
.withUser("lhh2").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
.and()
.withUser("lhh3").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3");
}
}