SpringSecurity的简单使用
目录
- 概述
- HelloWorld
- 依赖
- 写一个Controller
- 访问接口
- 用户认证
- 设置登录的用户名和密码
- 通过配置文件
- 通过配置类
- 自定义编写实现类
- 查询数据库的用户认证
- 自定义登录页面
- 用户授权
- 基于权限访问控制
- 单个权限hasAuthority
- 修改配置类
- 多个权限hasAnyAuthority
- 修改配置类
- 基于角色访问控制
- 基于单个角色访问控制hasRole
- 修改配置类
- 基于多个角色访问控制hasAnyRole
- 修改配置
- 自定义403页面
- 修改配置类
- 注解使用
- 开启注解功能
- @Secured
- @PreAuthorize
- @PostAuthorize
- @PreFilter
- @PostFilter
- 注销
- 自动登录
- 相关表结构
- 配置类相关内容
- CSRF
概述
SpringSecurity基于Spring框架,提供了一套Web应用安全性的完整解决方案,核心功能包括:用户认证、用户授权;
- 用户认证:
验证某个用户是否为系统中的合法主体,用户能否访问该系统。 - 用户授权:验证某个用户是否有权限执行某个操作。
SpringSecurity的特点:
- 和Spring无缝整合
- 全面的权限控制
- 专门为web开发而设计
1.旧版本不能脱离Web环境使用;
2.新版本对整个框架进行了分层抽取,分成了核心模块和Web模块,单独引入核心木块就可以脱离Web环境; - 重量级
**Shiro的特点:
- 轻量级:Shiro主张把复杂问题简单化,针对性能有更高要求的互联网应用有更好表现;
- 通用性:
1.好处:不局限于Web环境,可以头里Web环境使用
2.缺陷:在Web环境下的一些特定的需求需要手动编写代码定制
HelloWorld
依赖
<?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><groupId>per.xgt</groupId><artifactId>SpringSecurity-01-HelloWorld</artifactId><version>0.0.1-SNAPSHOT</version><name>SpringSecurity-01-HelloWorld</name><description>Demo project for Spring Boot</description><packaging>jar</packaging><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.2.1.RELEASE</spring-boot.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-security</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></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.3.7.RELEASE</version><configuration><mainClass>per.xgt.SpringSecurity01HelloWorldApplication</mainClass></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>
写一个Controller
package per.xgt.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @Author: gentao9527* @date: 2022/8/7 12:04* @Description: TODO* @Version: 1.0*/
@RestController
@RequestMapping("/test")
public class TestController {@RequestMapping("/hello")public String add(){return "hello";}}
访问接口
访问接口:http://localhost:8081/login
自动跳转到如下页面
默认登录用户名和密码:
默认的用户名是user
默认密码在控制台,如下:
用户认证
设置登录的用户名和密码
通过配置文件
# 应用名称
spring.application.name=SpringSecurity-01-HelloWorldserver.port=8081spring.security.user.name=admin
spring.security.user.password=123456
通过配置类
package per.xgt.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;/*** @Author: gentao9527* @date: 2022/8/7 14:15* @Description: TODO* @Version: 1.0*/
@Configuration
public class SecutiryConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {// 密码加密BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();String password = passwordEncoder.encode("123456");// 设置账号 密码 角色auth.inMemoryAuthentication().withUser("user").password(password).roles("admin");}/*** 注入 PasswordEncoder Bean* @return*/@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}}
自定义编写实现类
- 配置类
package per.xgt.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;/*** @Author: gentao9527* @date: 2022/8/7 15:52* @Description: TODO* @Version: 1.0*/
@Configuration
public class SecurityMyConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(password());}@Beanpublic PasswordEncoder password(){return new BCryptPasswordEncoder();}}
- userDetailsService的实现类
package per.xgt.service;import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;import java.util.List;/*** @Author: gentao9527* @date: 2022/8/7 15:56* @Description: TODO* @Version: 1.0*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {// 权限集合List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("test");// 用户认证return new User("xgt",new BCryptPasswordEncoder().encode("123456"),authorities);}
}
查询数据库的用户认证
- 依赖
<?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><groupId>per.xgt</groupId><artifactId>SpringSecurity-01-HelloWorld</artifactId><version>0.0.1-SNAPSHOT</version><name>SpringSecurity-01-HelloWorld</name><description>Demo project for Spring Boot</description><packaging>jar</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.1.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.2.1.RELEASE</spring-boot.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-security</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><!--mybatis-plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.0.5</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.3.7.RELEASE</version><configuration><mainClass>per.xgt.SpringSecurity01HelloWorldApplication</mainClass></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>
- 实体类
package per.xgt.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;/*** @Author: gentao9527* @date: 2022/8/7 16:21* @Description: TODO* @Version: 1.0*/
@Data
@TableName("users")
public class User {@TableId(value = "id",type = IdType.AUTO)private Integer id;@TableField(value = "userName")private String userName;@TableField(value = "password")private String password;}
- Mapper接口
package per.xgt.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import per.xgt.entity.User;/*** @author Valen* @version V1.0* @date 2022/8/7 16:27*/
@Mapper
public interface UserMapper extends BaseMapper<User> {}
- 在UserDetailsService实现类中用mapper获取账号密码
package per.xgt.service;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import per.xgt.mapper.UserMapper;import java.util.List;/*** @Author: gentao9527* @date: 2022/8/7 15:56* @Description: TODO* @Version: 1.0*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserMapper userMapper;/*** @param s 用户名* @return* @throws UsernameNotFoundException*/@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {// 调用mapper根据用户名查询数据库QueryWrapper<per.xgt.entity.User> wrapper = new QueryWrapper<>();wrapper.eq("userName",s);per.xgt.entity.User user = userMapper.selectOne(wrapper);if (null == user){// 没用这个用户throw new UsernameNotFoundException("用户不存在!");}// 权限集合List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("test");// 得到用户名和密码,返回return new User(user.getUserName(),new BCryptPasswordEncoder().encode(user.getPassword()),authorities);}
}
- 配置Mapper扫描
package per.xgt;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan(basePackages = "per.xgt.mapper")
public class SpringSecurity01HelloWorldApplication {public static void main(String[] args) {SpringApplication.run(SpringSecurity01HelloWorldApplication.class, args);}}
自定义登录页面
- 配置
package per.xgt.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;/*** @Author: gentao9527* @date: 2022/8/7 15:52* @Description: TODO* @Version: 1.0*/
@Configuration
public class SecurityMyConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(password());}@Beanpublic PasswordEncoder password(){return new BCryptPasswordEncoder();}/*** 配置自定义用户登录页面* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {// 自定义自己编写的登录页面http.formLogin()// 登录页面的地址.loginPage("/login.html")// 登录访问路径.loginProcessingUrl("/test/login")// 登录成功后访问的路径.defaultSuccessUrl("/test/index").permitAll().and().authorizeRequests()// 设置不需要认证可以访问的路径.antMatchers("/","/test/hello","/test/login").permitAll().anyRequest().authenticated()// 关闭CSRF防护.and().csrf().disable();}
}
- 相关页面
表单提交的账户名必须为username,密码必须为password;
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><form action="/test/login" method="post"><input type="text" name="username"><br><input type="password" name="password"><br><input type="submit" value="登录"></form>
</body>
</html>
- 引入thymeleaf
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>
- controller类
package per.xgt.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;/*** @Author: gentao9527* @date: 2022/8/7 12:04* @Description: TODO* @Version: 1.0*/
@Controller
@RequestMapping("/test")
public class TestController {@RequestMapping("/hello")@ResponseBodypublic String add(){return "hello";}@RequestMapping("/index")public String index(){return "index";}}
用户授权
基于权限访问控制
单个权限hasAuthority
如果当前的主题具有指定的权限则返回true,否则返回false
修改配置类
package per.xgt.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;/*** @Author: gentao9527* @date: 2022/8/7 15:52* @Description: TODO* @Version: 1.0*/
@Configuration
public class SecurityMyConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(password());}@Beanpublic PasswordEncoder password(){return new BCryptPasswordEncoder();}/*** 配置自定义用户登录页面* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {// 自定义自己编写的登录页面http.formLogin()// 登录页面的地址.loginPage("/login.html")// 登录访问路径.loginProcessingUrl("/test/login")// 登录成功后访问的路径.defaultSuccessUrl("/test/index").permitAll().and().authorizeRequests()// 设置不需要认证可以访问的路径.antMatchers("/","/test/hello","/test/login").permitAll()// 当前用户只有具有admin权限才可以访问这个路径.antMatchers("/test/index").hasAuthority("admin").anyRequest().authenticated()// 关闭CSRF防护.and().csrf().disable();}
}
package per.xgt.service;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import per.xgt.mapper.UserMapper;import java.util.List;/*** @Author: gentao9527* @date: 2022/8/7 15:56* @Description: TODO* @Version: 1.0*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserMapper userMapper;/*** @param s 用户名* @return* @throws UsernameNotFoundException*/@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {// 调用mapper根据用户名查询数据库QueryWrapper<per.xgt.entity.User> wrapper = new QueryWrapper<>();wrapper.eq("userName",s);per.xgt.entity.User user = userMapper.selectOne(wrapper);if (null == user){// 没用这个用户throw new UsernameNotFoundException("用户不存在!");}// 权限集合List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");// 得到用户名和密码,返回return new User(user.getUserName(),new BCryptPasswordEncoder().encode(user.getPassword()),authorities);}
}
多个权限hasAnyAuthority
修改配置类
package per.xgt.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;/*** @Author: gentao9527* @date: 2022/8/7 15:52* @Description: TODO* @Version: 1.0*/
@Configuration
public class SecurityMyConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(password());}@Beanpublic PasswordEncoder password(){return new BCryptPasswordEncoder();}/*** 配置自定义用户登录页面* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {// 自定义自己编写的登录页面http.formLogin()// 登录页面的地址.loginPage("/login.html")// 登录访问路径.loginProcessingUrl("/test/login")// 登录成功后访问的路径.defaultSuccessUrl("/test/index").permitAll().and().authorizeRequests()// 设置不需要认证可以访问的路径.antMatchers("/","/test/hello","/test/login").permitAll()// 当前用户只有具有admin权限才可以访问这个路径
// .antMatchers("/test/index").hasAuthority("admin").antMatchers("/test/index").hasAnyAuthority("admin","manager").anyRequest().authenticated()// 关闭CSRF防护.and().csrf().disable();}
}
基于角色访问控制
如果用户具备给定角色就返回true:允许访问,否则出现403
基于单个角色访问控制hasRole
修改配置类
package per.xgt.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;/*** @Author: gentao9527* @date: 2022/8/7 15:52* @Description: TODO* @Version: 1.0*/
@Configuration
public class SecurityMyConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(password());}@Beanpublic PasswordEncoder password(){return new BCryptPasswordEncoder();}/*** 配置自定义用户登录页面* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {// 自定义自己编写的登录页面http.formLogin()// 登录页面的地址.loginPage("/login.html")// 登录访问路径.loginProcessingUrl("/test/login")// 登录成功后访问的路径.defaultSuccessUrl("/test/index").permitAll().and().authorizeRequests()// 设置不需要认证可以访问的路径.antMatchers("/","/test/hello","/test/login").permitAll()// 当前用户只有具有admin权限才可以访问这个路径
// .antMatchers("/test/index").hasAuthority("admin")
// .antMatchers("/test/index").hasAnyAuthority("admin","manager")// 当前角色只有是admin角色才可以访问.antMatchers("/test/index").hasRole("admin").anyRequest().authenticated()// 关闭CSRF防护.and().csrf().disable();}
}
package per.xgt.service;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import per.xgt.mapper.UserMapper;import java.util.List;/*** @Author: gentao9527* @date: 2022/8/7 15:56* @Description: TODO* @Version: 1.0*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserMapper userMapper;/*** @param s 用户名* @return* @throws UsernameNotFoundException*/@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {// 调用mapper根据用户名查询数据库QueryWrapper<per.xgt.entity.User> wrapper = new QueryWrapper<>();wrapper.eq("userName",s);per.xgt.entity.User user = userMapper.selectOne(wrapper);if (null == user){// 没用这个用户throw new UsernameNotFoundException("用户不存在!");}// 权限集合List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("manager,ROLE_admin");// 得到用户名和密码,返回return new User(user.getUserName(),new BCryptPasswordEncoder().encode(user.getPassword()),authorities);}
}
在验证是否具有当前角色的时候,String会自动在前面拼接一个"ROLE_",所以存储用户角色的时候可以加上前缀
基于多个角色访问控制hasAnyRole
修改配置
表示用户用户具备任何一个条件都可以访问
package per.xgt.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;/*** @Author: gentao9527* @date: 2022/8/7 15:52* @Description: TODO* @Version: 1.0*/
@Configuration
public class SecurityMyConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(password());}@Beanpublic PasswordEncoder password(){return new BCryptPasswordEncoder();}/*** 配置自定义用户登录页面* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {// 自定义自己编写的登录页面http.formLogin()// 登录页面的地址.loginPage("/login.html")// 登录访问路径.loginProcessingUrl("/test/login")// 登录成功后访问的路径.defaultSuccessUrl("/test/index").permitAll().and().authorizeRequests()// 设置不需要认证可以访问的路径.antMatchers("/","/test/hello","/test/login").permitAll()// 当前用户只有具有admin权限才可以访问这个路径
// .antMatchers("/test/index").hasAuthority("admin")
// .antMatchers("/test/index").hasAnyAuthority("admin","manager")// 当前角色只有是admin角色才可以访问
// .antMatchers("/test/index").hasRole("admin").antMatchers("/test/index").hasAnyRole("admin,manager").anyRequest().authenticated()// 关闭CSRF防护.and().csrf().disable();}
}
自定义403页面
修改配置类
配置没有权限返回跳转到指定的自定义的页面
package per.xgt.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;/*** @Author: gentao9527* @date: 2022/8/7 15:52* @Description: TODO* @Version: 1.0*/
@Configuration
public class SecurityMyConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(password());}@Beanpublic PasswordEncoder password(){return new BCryptPasswordEncoder();}/*** 配置自定义用户登录页面* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {// 配置没有权限访问跳转到自己自定义的页面http.exceptionHandling().accessDeniedPage("/error/unAuth.html");// 自定义自己编写的登录页面http.formLogin()// 登录页面的地址.loginPage("/login.html")// 登录访问路径.loginProcessingUrl("/test/login")// 登录成功后访问的路径.defaultSuccessUrl("/test/index").permitAll().and().authorizeRequests()// 设置不需要认证可以访问的路径.antMatchers("/","/test/hello","/test/login").permitAll()// 当前用户只有具有admin权限才可以访问这个路径
// .antMatchers("/test/index").hasAuthority("admin")
// .antMatchers("/test/index").hasAnyAuthority("admin","manager")// 当前角色只有是admin角色才可以访问
// .antMatchers("/test/index").hasRole("admin").antMatchers("/test/index").hasAnyRole("admin,manager").anyRequest().authenticated()// 关闭CSRF防护.and().csrf().disable();}
}
错误页面必须以 “/” 开始
注解使用
开启注解功能
将 @EnableGlobalMethodSecurity(securedEnabled = true) 放在启动了或者配置类上
@Secured
在controller的方法上使用注解 @Secured :用户具有某个角色,可以访问方法
@RequestMapping("/update")@ResponseBody@Secured({"ROLE_haha","ROLE_hehe"})public String update(){return "index";}
@PreAuthorize
适合进入方法前的权限验证,可以将登录用户的roles/permissions参数传到方法中
需要开启相关功能
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
在Controller方法上添加注解
@RequestMapping("/update")@ResponseBody@PreAuthorize("hasAnyRole('admin')")public String update(){return "index";}
@PostAuthorize
在方法执行后再进行权限验证,适合验证带有返回值的权限
需要开启相关功能
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
在方法上添加注解
@RequestMapping("/update")@ResponseBody@PostAuthorize("hasAnyAuthority('admins')")public String update(){System.out.println("update......");return "index";}
即使没有权限访问,方法也执行了
@PreFilter
传入方法数据进行过滤
@RequestMapping("update")@PreAuthorize("hasRole('ROLE_admin')")@PreFilter(value = "filterObject.id%2==0")@ResponseBodypublic List<User> update(@RequestBody List<User>list){list.forEach(t-> {System.out.println(t.getId()+"\t"+t.getUserName());});return list;}
@PostFilter
方法返回数据进行过滤
@RequestMapping("/update")@ResponseBody@PostAuthorize("hasAnyAuthority('admin')")@PostFilter(value = "filterObject.userName == admin")public List<User> update(){List list = new ArrayList<User>();list.add(new User(1,"xgt","xgt"));list.add(new User(2,"admin","admin"));return list;}
注销
/*** 配置自定义用户登录页面* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {// 退出登录http.logout().logoutUrl("/logout").logoutSuccessUrl("/test/hello").permitAll();// 配置没有权限访问跳转到自己自定义的页面http.exceptionHandling().accessDeniedPage("/error/unAuth.html");// 自定义自己编写的登录页面http.formLogin()// 登录页面的地址.loginPage("/login.html")// 登录访问路径.loginProcessingUrl("/test/login")// 登录成功后访问的路径.defaultSuccessUrl("/test/index").permitAll().and().authorizeRequests()// 设置不需要认证可以访问的路径.antMatchers("/","/test/hello","/test/login").permitAll()// 当前用户只有具有admin权限才可以访问这个路径
// .antMatchers("/test/index").hasAuthority("admin")
// .antMatchers("/test/index").hasAnyAuthority("admin","manager")// 当前角色只有是admin角色才可以访问
// .antMatchers("/test/index").hasRole("admin").antMatchers("/test/index").hasAnyRole("admin,manager").anyRequest().authenticated()// 关闭CSRF防护.and().csrf().disable();}
自动登录
相关表结构
CREATE TABLE `persistent_logins` (
`username` varchar(64) NOT NULL,
`series` varchar(64) NOT NULL,
`token` varchar(64) NOT NULL,
`last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE
CURRENT_TIMESTAMP,
PRIMARY KEY (`series`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
配置类相关内容
注册相关数据库操作对象 注入数据源
/*** 配置数据库操作对象* @return*/@Beanpublic PersistentTokenRepository persistentTokenRepository(){JdbcTokenRepositoryImpl repository = new JdbcTokenRepositoryImpl();// 可以自动生成相关表//repository.setCreateTableOnStartup(true);repository.setDataSource(dataSource);return repository;}
配置类中配置自动登录
package per.xgt.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;import javax.sql.DataSource;/*** @Author: gentao9527* @date: 2022/8/7 15:52* @Description: TODO* @Version: 1.0*/
@Configuration
public class SecurityMyConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate DataSource dataSource;/*** 配置数据库操作对象* @return*/@Beanpublic PersistentTokenRepository persistentTokenRepository(){JdbcTokenRepositoryImpl repository = new JdbcTokenRepositoryImpl();// 可以自动生成相关表//repository.setCreateTableOnStartup(true);repository.setDataSource(dataSource);return repository;}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(password());}@Beanpublic PasswordEncoder password(){return new BCryptPasswordEncoder();}/*** 配置自定义用户登录页面* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {// 退出登录http.logout().logoutUrl("/logout").logoutSuccessUrl("/test/hello").permitAll();// 配置没有权限访问跳转到自己自定义的页面http.exceptionHandling().accessDeniedPage("/error/unAuth.html");// 自定义自己编写的登录页面http.formLogin()// 登录页面的地址.loginPage("/login.html")// 登录访问路径.loginProcessingUrl("/test/login")// 登录成功后访问的路径.defaultSuccessUrl("/test/index").permitAll().and().authorizeRequests()// 设置不需要认证可以访问的路径.antMatchers("/","/test/hello","/test/login").permitAll()// 当前用户只有具有admin权限才可以访问这个路径
// .antMatchers("/test/index").hasAuthority("admin")
// .antMatchers("/test/index").hasAnyAuthority("admin","manager")// 当前角色只有是admin角色才可以访问
// .antMatchers("/test/index").hasRole("admin").antMatchers("/test/index").hasAnyRole("admin,manager").anyRequest().authenticated().and().rememberMe().tokenRepository(persistentTokenRepository()).tokenValiditySeconds(600).userDetailsService(userDetailsService)// 关闭CSRF防护.and().csrf().disable();}
}
登录页,name必须是 remember-me
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><form action="/test/login" method="post"><input type="text" name="username"><br><input type="password" name="password"><br><input type="submit" value="登录"><br><input type="checkbox" name="remember-me"></form>
</body>
</html>
CSRF
配置类中启用csrf防护机制(SpringSecurity4.0开始默认开启)
@Overrideprotected void configure(HttpSecurity http) throws Exception {// 退出登录http.logout().logoutUrl("/logout").logoutSuccessUrl("/test/hello").permitAll();// 配置没有权限访问跳转到自己自定义的页面http.exceptionHandling().accessDeniedPage("/error/unAuth.html");// 自定义自己编写的登录页面http.formLogin()// 登录页面的地址.loginPage("/login.html")// 登录访问路径.loginProcessingUrl("/test/login")// 登录成功后访问的路径.defaultSuccessUrl("/test/index").permitAll().and().authorizeRequests()// 设置不需要认证可以访问的路径.antMatchers("/","/test/hello","/test/login").permitAll()// 当前用户只有具有admin权限才可以访问这个路径
// .antMatchers("/test/index").hasAuthority("admin")
// .antMatchers("/test/index").hasAnyAuthority("admin","manager")// 当前角色只有是admin角色才可以访问
// .antMatchers("/test/index").hasRole("admin").antMatchers("/test/index").hasAnyRole("admin,manager").anyRequest().authenticated().and().rememberMe().tokenRepository(persistentTokenRepository()).tokenValiditySeconds(600).userDetailsService(userDetailsService)// 关闭CSRF防护.and().csrf().disable();}
在登录页添加一个隐藏域
<input
type="hidden"th:if="${_csrf}!=null"th:value="${_csrf.token}"name="_csrf />
SpringSecurity的简单使用相关推荐
- SpringSecurity的简单概述以及配置SpringSecurity的默认登录页面
SpringSecurity的简单概述 是什么:SpringSecurity融合Spring技术栈,提供JavaEE应 用的整体安全解决方案:提供全面的安全服务 有什么用:可以进行身份验证,就是证明你 ...
- SpringSecurity的简单应用(一)
java项目首先要提的就是jar包了,Springsecurity的jar下载地址:http://static.springsource.org/spring-security/site/downlo ...
- SpringSecurity的简单使用使用案列说明
SpringSecurity Spring Security是 Spring提供的安全认证服务的框架. 使用Spring Security可以帮助我们来简化认证 和授权的过程.官网:https://s ...
- SpringSecurity 简单使用
SpringSecurity 简单使用 在 Web 开发中安全是不可忽视的问题(软件安全技术!),现在从 SpringSecurity 和 Shiro 两个框架来学习一下安全框架在 Web 应用中的使 ...
- Spring Security详细讲解(JWT+SpringSecurity登入案例)
本篇博文目录: 一.SpringSecurity简介 1.SpringSecurity 2.SpringSecurity相关概念 二.认证和授权 1.认证 (1) 使用SpringSecurity进行 ...
- JAVA-WBE——spring security 3.2 认证-学习笔记2
2019独角兽企业重金招聘Python工程师标准>>> spring-security.xml 简单实现用户登录 (不连接数据库) <?xml version="1. ...
- 【Java从0到架构师】项目实战 - 会话管理、EhCache、JWT、权限管理 Shiro、打包部署
项目实战 - 权限管理 会话管理 客户端身份认证 - 基于 Cookie.Session 客户端身份验证 - 基于 token EhCache - 简单的缓存框架 JWT - 基于 JSON 的 to ...
- SpringBoot使用security实现OAuth2
SpringBoot使用security实现OAuth2 OAuth2 OAuth是一个开放标准,允许用户授权地方应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方应用或者 ...
- SpringSecurity使用SpringBoot简单使用
SpringSecurity使用SpringBoot简单使用(一) 先来回顾下最开始我们不用框架时是怎么做认证授权的, 1.不用框架认证流程 1.客户端发送请求,controller层将请求对象封装成 ...
最新文章
- 规格表管理之保存规格表数据表数据
- PHP的学习--Traits新特性
- 英国脱欧但网络安全领域重视未减
- 【错误记录】Android Studio 中查看 Gradle 配置的方法源码 ( 配置 gradle-wrapper.properties 中版本为 gradle-x.x.x-all.zip )
- oracle表空间的创建及dmp 文件的导入
- 嵌入式编程-C语言使用小技巧
- iframe 高度根据子页面来确定
- __main代码分析
- VerbalExpressions
- maven与ant的区别
- 4台服务器集群搭建_Redis Cluster高可用集群搭建
- setuna.exe在win10下使用,桌面自动放大问题
- 《动手学深度学习》网页版
- 科幻-奇幻小说TOP100
- 库存管理中的 (s, S) 策略,K convex,K 凸
- Vue3 使用marked【代码高亮,安装使用教程】
- 计算机三级嵌入式学习笔记(一)
- JavaScript高级之42个英语单词
- 华为手机主界面的返回键怎么调出来_主按钮怎么变回来 华为手机的返回键怎么设置?...
- continue的用法