目录

  • 概述
  • 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的简单使用相关推荐

  1. SpringSecurity的简单概述以及配置SpringSecurity的默认登录页面

    SpringSecurity的简单概述 是什么:SpringSecurity融合Spring技术栈,提供JavaEE应 用的整体安全解决方案:提供全面的安全服务 有什么用:可以进行身份验证,就是证明你 ...

  2. SpringSecurity的简单应用(一)

    java项目首先要提的就是jar包了,Springsecurity的jar下载地址:http://static.springsource.org/spring-security/site/downlo ...

  3. SpringSecurity的简单使用使用案列说明

    SpringSecurity Spring Security是 Spring提供的安全认证服务的框架. 使用Spring Security可以帮助我们来简化认证 和授权的过程.官网:https://s ...

  4. SpringSecurity 简单使用

    SpringSecurity 简单使用 在 Web 开发中安全是不可忽视的问题(软件安全技术!),现在从 SpringSecurity 和 Shiro 两个框架来学习一下安全框架在 Web 应用中的使 ...

  5. Spring Security详细讲解(JWT+SpringSecurity登入案例)

    本篇博文目录: 一.SpringSecurity简介 1.SpringSecurity 2.SpringSecurity相关概念 二.认证和授权 1.认证 (1) 使用SpringSecurity进行 ...

  6. JAVA-WBE——spring security 3.2 认证-学习笔记2

    2019独角兽企业重金招聘Python工程师标准>>> spring-security.xml 简单实现用户登录 (不连接数据库) <?xml version="1. ...

  7. 【Java从0到架构师】项目实战 - 会话管理、EhCache、JWT、权限管理 Shiro、打包部署

    项目实战 - 权限管理 会话管理 客户端身份认证 - 基于 Cookie.Session 客户端身份验证 - 基于 token EhCache - 简单的缓存框架 JWT - 基于 JSON 的 to ...

  8. SpringBoot使用security实现OAuth2

    SpringBoot使用security实现OAuth2 OAuth2 OAuth是一个开放标准,允许用户授权地方应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方应用或者 ...

  9. SpringSecurity使用SpringBoot简单使用

    SpringSecurity使用SpringBoot简单使用(一) 先来回顾下最开始我们不用框架时是怎么做认证授权的, 1.不用框架认证流程 1.客户端发送请求,controller层将请求对象封装成 ...

最新文章

  1. 规格表管理之保存规格表数据表数据
  2. PHP的学习--Traits新特性
  3. 英国脱欧但网络安全领域重视未减
  4. 【错误记录】Android Studio 中查看 Gradle 配置的方法源码 ( 配置 gradle-wrapper.properties 中版本为 gradle-x.x.x-all.zip )
  5. oracle表空间的创建及dmp 文件的导入
  6. 嵌入式编程-C语言使用小技巧
  7. iframe 高度根据子页面来确定
  8. __main代码分析
  9. VerbalExpressions
  10. maven与ant的区别
  11. 4台服务器集群搭建_Redis Cluster高可用集群搭建
  12. setuna.exe在win10下使用,桌面自动放大问题
  13. 《动手学深度学习》网页版
  14. 科幻-奇幻小说TOP100
  15. 库存管理中的 (s, S) 策略,K convex,K 凸
  16. Vue3 使用marked【代码高亮,安装使用教程】
  17. 计算机三级嵌入式学习笔记(一)
  18. JavaScript高级之42个英语单词
  19. 华为手机主界面的返回键怎么调出来_主按钮怎么变回来 华为手机的返回键怎么设置?...
  20. continue的用法

热门文章

  1. 学习linux命令finalshell使用及所碰到的问题
  2. 运营 | 你知道短视频的思路规划吗?
  3. C#事件与委托(详解)
  4. html代码设置五边形,所需的五边形形状,正确的方向CSS和HTML
  5. 计算机音乐在线使用,自制在线音乐播放平台,电脑办公者100%好评。
  6. UVA10391-复合词
  7. 骁龙865和麒麟990哪个好
  8. iOS开发-Interface Builder的前世今生
  9. itext设置pdf的尺寸_java-iText PDFDocument页面大小不正确
  10. 砍价算法,随机金额砍价代码,可以参考一下