Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >分布式--Spring Security入门

分布式--Spring Security入门

作者头像
aruba
发布于 2022-09-19 07:55:29
发布于 2022-09-19 07:55:29
74200
代码可运行
举报
文章被收录于专栏:android技术android技术
运行总次数:0
代码可运行

Spring Security是Spring推出的一个安全框架,说白了就是争对用户登录和权限的框架,所以主要功能为两块:“认证”和“授权”,对应用户登录和是否有权限去访问一些功能

一、使用Spring Security

1. 依赖

SpringBoot项目中加入依赖:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
2. 写一个测试接口
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@RestController
public class DemoController {

    @RequestMapping("/demo")
    public String demo(){
        return "demo";
    }

}

访问:http://localhost:8080/demo 后,跳转的为:

默认账号为:user,密码在启动时的控制台输出:

输入账号密码后登录,就可以成功的访问接口了:

二、自定义登录逻辑

实际登录中,用户的账号密码肯定需要通过数据库查询匹配,官方默认只提供了一个默认账号,那么如何自定义用户的登录逻辑呢?

1. UserDetailsService

UserDetailsService接口需要实现loadUserByUsername()方法,该方法返回一个UserDetails对象,该对象是一个接口,其方法对应的解释看下面的注解:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface UserDetails extends Serializable {
    // 权限列表
    Collection<? extends GrantedAuthority> getAuthorities();

    // 密码
    String getPassword();

    String getUsername();

    // 账号是否过期
    boolean isAccountNonExpired();

    // 账号是否被锁定
    boolean isAccountNonLocked();

    // 凭证是否过期
    boolean isCredentialsNonExpired();

    // 是否可以
    boolean isEnabled();
}

其实现类为User

实现UserDetailsService接口,并使用实现类User构造UserDetailsUser构造传入三个参数:用户名、密码、权限列表,密码需要通过PasswordEncoder将原密码进行编码后传入,会自动和前端传入的密码进行匹配,权限暂时构造空的即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 模拟数据库查询操作
        if (!username.equals("aruba")) throw new UsernameNotFoundException("用户未找到");
        // 查询出的密码
        String pwd = "123";

        // 密码解析器
        String encodePassword = passwordEncoder.encode(pwd);
        User user = new User(username, encodePassword, AuthorityUtils.commaSeparatedStringToAuthorityList(""));

        return user;
    }
}
2. PasswordEncoder

密码解析器PasswordEncoder接口的方法解释:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface PasswordEncoder {

    // 进行编码
    String encode(CharSequence rawPassword);

    // 原密码和编码后的密码是否匹配
    boolean matches(CharSequence rawPassword, String encodedPassword);

    // 编码的密码能够再次进行解析且达到更安全的结果则返回true
    default boolean upgradeEncoding(String encodedPassword) {
        return false;
    }
}

密码解析器实现类有很多:

我们使用最常用的BCryptPasswordEncoder

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
public class PasswordEncoderConfig {

    /**
     * 提供PasswordEncoder
     *
     * @return
     */
    @Bean
    protected PasswordEncoder providerPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

重启项目,进行访问,此时我们可以使用自定义的账号和密码进行登录了

三、自定义登录界面

上面自定义了登录逻辑,现在来对登录界面进行配置

1. 依赖

导入模板引擎:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
2. 页面编写

SpringSecurity中默认使用usernamepassword作为登录的请求参数,默认登录接口:/login,使用post请求

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/login" method="post">
    用户名:<input type="text" value="" name="username"><br/>
    密码: <input type="password" name="password"><br/>

    <input type="submit" value="登录">
</form>
</body>
</html>
3. SecurityFilterChain

提供注入SecurityFilterChain的方法,该方法有一个入参为HttpSecurity

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
public class SecurityConfig {

    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.formLogin().loginPage("/showLogin")//登录页面处理单元
                .loginProcessingUrl("/login")//登录时提交的请求
                .successForwardUrl("/main");//登录成功处理单元

        http.authorizeRequests()
                .antMatchers("/showLogin").permitAll() //配置不需要被认证的请求
                .anyRequest().authenticated();//其他请求都必须被认证。必须登录后才能访问。

        http.csrf().disable();

        return http.build();
    }
}
4. controller编写
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Controller
public class LoginController {

    @RequestMapping("/showLogin")
    public String showLogin() {
        return "login";
    }

    @RequestMapping("/main")
    @ResponseBody
    public String main() {
        return "main";
    }

}

访问效果:

5. handler

除了使用successForwardUrl方法指定成功转发的目标外,还可以通过handler做自己想要的处理,比如使用重定向,此处SpringSecurity不会做授权控制:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        http.formLogin().loginPage("/showLogin")//登录页面处理单元
                .loginProcessingUrl("/login")//登录时提交的请求
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        response.sendRedirect("/main");
                    }
                });

此外还有失败的处理:failureHandler(AuthenticationFailureHandler)方法,使用上是一样的

四、URL匹配

1. antMatchers通配符

上面我们已经使用过antMatchers()方法来指定哪些请求不需要授权,它还支持通配符

通配符

描述

?

匹配一个字符

*

匹配0个或多个字符

**

匹配0个或多个目录

如放行js目录下的所有文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.antMatchers("/js/**").permitAll()
2. antMatchers指定请求方式

通过第一个参数,使用HttpMethod指定请求方式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.antMatchers(HttpMethod.GET,"/js/**").permitAll()

除了antMatchers()方法以外,还可以使用regexMatchers()方法,匹配规则为正则表达式

五、角色权限判断

1. 设置请求的角色权限

Spring Security权限分为两种:权限角色,一个用户可以拥有多个角色,而一个角色可以拥有不同的权限

下面为配置权限的方法,在URL匹配后调用

权限方法

描述

hasAuthority(String)

只有拥有传入参数:权限,才允许访问

hasAnyAuthority(String ...)

拥有任意一个权限,都可以访问

hasRole(String)

只有具备传入参数:角色 ,才允许访问

hasAnyRole(String ...)

拥有任意一个角色,都可以访问

hasIpAddress(String)

指定ip,才可以访问

示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.antMatchers("/register").hasAuthority("register")//只有有注册权限
.antMatchers("/modify").hasAnyAuthority("modify","register")//任意一个权限
.antMatchers("/manage").hasRole("admin")//只有admin角色
.antMatchers("/show").hasAnyRole("admin","user")//任意一个角色
2. 分配用户的角色权限

上面只是争对不同的请求配置了权限和角色,想要用户拥有权限和角色,就需要在UserDetails中进行添加,之前我们权限暂时设置为了空。 权限和角色设置规则:多个权限和角色使用,分开,角色需要添加ROLE_前缀:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
User user = new User(username, encodePassword, 
        AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_admin,modify"));
3. 拒绝权限处理

successHandler()一样,Spring Security也可以自定义拒绝权限的处理,使用accessDeniedHandler(AccessDeniedHandler)方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 拒绝访问的处理
http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        response.setHeader("Content-Type", "application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.write("{\"status\":\"error\",\"msg\":\"权限不足,请联系管理员!\"}");
        out.flush();
        out.close();
    }
});
4. 权限自定义判断

针对一些特殊的需求,我们可能要自定义权限的判断逻辑,Spring Security也支持,只要按照它提供的规则进行代码编写

4.1 boolean hasPermission(HttpServletRequest,Authentication)

需要定义一个接口,里面有该方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface MyAccessService {
    boolean hasPermission(HttpServletRequest request, Authentication authentication);
}

实现接口:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Service
public class MyAccessServiceImpl implements MyAccessService {
    @Override
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        // 获取对象
        Object principal = authentication.getPrincipal();
        if (principal instanceof UserDetails) {
            // 转为UserDetails对象
            UserDetails userDetails = (UserDetails) principal;
            // 获取所有权限
            Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
            // 做自己的处理
            return authorities.contains(new SimpleGrantedAuthority("ROLE_admin"));
        }
        return false;
    }
}
4.2 使用自定义

通过@+注入bean的方式调用方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.anyRequest().access("@myAccessServiceImpl.hasPermission(request,authentication)");
5. 注解设置请求权限

除了通过config方式外,还可以通过注解来指定controller层哪个请求使用哪些权限,需要在SpringBoot启动类上开启@EnableMethodSecurity注解:

支持的注解有:

注解

描述

@Secured

指定处理单元的权限和角色,参数为数组,使用需要开启@EnableMethodSecurity注解的securedEnabled

@PreAuthorize

在处理单元之前进行权限和角色的控制,使用权限表达式进行授权

@PostAuthorize

在处理单元之后进行权限和角色的控制

示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@RestController
public class DemoController {

    // Secured角色需要加上ROLE前缀
    @Secured({"ROLE_admin", "register"})
    @RequestMapping("/demo")
    public String demo() {
        return "demo";
    }

    // PreAuthorize中可以调用方法
    @PreAuthorize("hasRole('admin')")
    @RequestMapping("/demo2")
    public String demo2() {
        return "demo";
    }
}

六、记住登录

Spring Security记住登录功能依赖数据库实现,需要进行以下配置

1. 依赖
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
       <dependency>
           <groupId>org.mybatis.spring.boot</groupId>
           <artifactId>mybatis-spring-boot-starter</artifactId>
           <version>2.1.3</version>
       </dependency>
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <version>8.0.21</version>
       </dependency>

yml中进行配置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
2. PersistentTokenRepository

提供PersistentTokenRepository,使用它的实现类:JdbcTokenRepositoryImpl

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
public class RememberConfig {

    @Autowired
    private DataSource dataSource;

    @Bean
    protected PersistentTokenRepository providerTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        // 启动时,自动创建表,第二次启动注释
        jdbcTokenRepository.setCreateTableOnStartup(true);
        jdbcTokenRepository.setDataSource(dataSource);

        return jdbcTokenRepository;
    }

}
3. 配置HttpSecurity
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        // 持久处理
        http.rememberMe()
                .userDetailsService(userDetailsService) //登录逻辑交给哪个对象
                .tokenValiditySeconds(5000) // 表示持久化时间
                .tokenRepository(repository);   //持久层对象
4. 页面添加标签

添加nameremember-me的标签:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
记住: <input type="checkbox" name="remember-me"><br/>

之后网页只需要登录一次,就可以持久5000s不需要登录,即使服务重启也可以保持登录状态

项目地址:

https://gitee.com/aruba/spring-security-study.git

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-08-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
SpringBoot集成Spring Security(1)——入门程序
因为项目需要,第一次接触 Spring Security,早就听闻 Spring Security 功能强大但上手困难,学习了几天出入门道,特整理这篇文章希望能让后来者少踩一点坑(本文附带实例程序,请放心食用)
全栈程序员站长
2022/09/09
8470
SpringBoot集成Spring Security(1)——入门程序
【Spring Security】003-Spring Security web权限方案(1):用户认证
在resources目录下创建static目录,并创建login.html,name必须是username和password;
訾博ZiBo
2025/01/06
1180
【Spring Security】003-Spring Security web权限方案(1):用户认证
重学SpringBoot3-集成Spring Security(四)
在现代应用开发中,安全性和数据管理是两大重要模块。Spring Security 提供了全面的安全解决方案,而 Spring Data JPA 则简化了与数据库的交互。将两者结合,可以在保护应用的同时,轻松实现基于用户身份的访问控制、权限管理和安全的数据存储操作。
CoderJia
2024/10/20
3990
重学SpringBoot3-集成Spring Security(四)
使用Spring Boot实现用户认证和授权
在现代Web应用中,用户认证和授权是必不可少的功能。它们确保只有经过验证的用户才能访问应用,并根据用户的角色和权限进行相应的操作。Spring Boot通过集成Spring Security,提供了强大的安全功能,简化了用户认证和授权的实现。本文将详细探讨如何使用Spring Boot实现用户认证和授权,并提供具体的代码示例和应用案例。
E绵绵
2024/06/23
4830
Spring Security和JWT实现登录授权认证
IUserService的实现类,注册时会将用户权限设置为ROLE_USER,同时将密码使用BCrypt加密
朝雨忆轻尘
2019/06/18
4.8K2
Spring Security 最佳实践,看了必懂!
点击上方“芋道源码”,选择“设为星标” 管她前浪,还是后浪? 能浪的浪,才是好浪! 每天 10:33 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | Java 2021 超神之路,很肝~ 中文详细注释的开源项目 RPC 框架 Dubbo 源码解析 网络应用框架 Netty 源码解析 消息中间件 RocketMQ 源码解析 数据库中间件 Sharding-JDBC 和 MyCAT 源码解析 作业调度中间件 Elastic-Job 源码解析 分布式事务中间件 TCC-Transaction
芋道源码
2022/09/07
9630
Spring Security 最佳实践,看了必懂!
springboot+security整合1
  Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
用户2038589
2018/09/06
9780
springboot+security整合1
springboot+security整合(1)
  Spring Security 是一个能够为基于 Spring 的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在 Spring 应用上下文中配置的 Bean,充分利用了 Spring IoC,DI(控制反转 Inversion of Control ,DI:Dependency Injection 依赖注入)和 AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
用户2038589
2019/05/17
5170
springboot+security整合(1)
SpringBoot整合Security
Security作为Spring的官方安全框架,自然为SpringBoot提供了起步依赖(Starter),有了起步依赖,我们只要添加少量的Java配置,就可以把Security集成到SpringBoot项目中。
用户10175992
2022/11/15
1.2K0
SpringBoot整合Security
Spring Security入门案例
IoC/DI和AOP功能,为系统提供了声明式安全访问控制功能,减少了为系统安全而编写大量重复代码的工作。主要包含如下几个重要的内容:
ruochen
2021/11/25
1.3K0
Spring boot项目集成security
在进行框架选型时最常用的选择就是在Spring security 和Shiro中进行抉择,Spring security 和 shiro 一样,都具有认证、授权、加密等用于权限管理的功能。但是对于Springboot而言,Spring Security比Shiro更合适一些,他们都是Spring生态里的内容,并且在使用上Spring boot只需要引入Security就可以实现基础的登陆验证。
余生大大
2022/11/02
3890
Spring boot项目集成security
Spring全家桶之SpringSecurity
SpringSecurity 是一个高度自定义的安全框架。利用 SpringIoC/DI和 AOP 功能,为系统提供了声明式安全访问控制功能,减少了为系统安全而编写大量重复代码的工作。使用 SpringSecruity 的原因有很多,但大部分都是发现了 javaEE的 Servlet 规范或 EJB 规范中的安全功能缺乏典型企业应用场景。同时认识到他们在 WAR 或 EAR 级别无法移植。因此如果你更换服务器环境,还需要大量工作去重新配置你的应用程序。使用 SpringSecurity解决了这些问题,也为你提供许多其他有用的、可定制的安全功能。
时间静止不是简史
2020/07/27
3.6K0
Spring全家桶之SpringSecurity
SpringSecurity + JWT,从入门到精通!
RBAC 全称为基于角色的权限控制,本段将会从什么是 RBAC,模型分类,什么是权限,用户组的使用,实例分析等几个方面阐述 RBAC,绘制思维导图如下:
后端码匠
2020/07/14
5.6K3
Spirng Security知识点整理
访问controller,首先请求会被安全框架的aop机制拦截,要求使用用户名和密码验证登录
大忽悠爱学习
2021/12/07
1.6K0
Spirng Security知识点整理
Spring Security的认证和授权
Spring Security是为基于Spring的应用程序提供声明式安全保护的安全性框架。Spring Security提供了完整的安全性解决方案,它能够在Web请求级别和方法调用级别处理身份认证和授权。因为基于Spring框架,所以Spring Security充分利用了依赖注入(dependency injection,DI)和面向切面(AOP)的技术。
兜兜转转
2023/03/29
2.4K0
Spring Security的认证和授权
万字搞定 Spring Security!
RBAC 全称为基于角色的权限控制,本段将会从什么是 RBAC,模型分类,什么是权限,用户组的使用,实例分析等几个方面阐述 RBAC.
用户2242639
2023/09/02
3130
万字搞定 Spring Security!
Spring 全家桶之 Spring Security(二)
&emsp;&emsp;授权的主要作用是给登录系统的用户的角色授予该角色角色所能访问的菜单列表或者能操作的功能
RiemannHypothesis
2022/08/19
4330
Spring 全家桶之 Spring Security(二)
4万字!Spring Security 从入门到精通!
Spring Security 是 Spring 家族中的一个安全管理框架。相比与另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富。
一行Java
2023/02/23
6900
4万字!Spring Security 从入门到精通!
springboot第22集:security,Lombok,token,redis
Spring Security是一个基于Spring框架的权限管理框架,用于帮助应用程序实现身份验证和授权功能。它可以为Web应用程序、REST API和方法级安全性提供支持,并支持各种认证方式。
达达前端
2023/10/08
5450
springboot第22集:security,Lombok,token,redis
【Spring Security】005-Spring Security web权限方案(3):用户注销、自动登录、CSRF功能
访问http://localhost:8111/login.html进行登录,并勾选自动登陆选项
訾博ZiBo
2025/01/06
1260
【Spring Security】005-Spring Security web权限方案(3):用户注销、自动登录、CSRF功能
推荐阅读
相关推荐
SpringBoot集成Spring Security(1)——入门程序
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验