springboot+security整合(1)

说明 springboot 版本 2.0.3
源码地址:点击跳转

系列

一、 介绍

??Spring Security 是一个能够为基于 Spring 的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在 Spring 应用上下文中配置的 Bean,充分利用了 Spring IoC,DI(控制反转 Inversion of Control ,DI:Dependency Injection 依赖注入)和 AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

二、 环境搭建

??建立 springboot2 项目,加入 security 依赖,mybatis 依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
   <groupId>org.mybatis.spring.boot</groupId>
   <artifactId>mybatis-spring-boot-starter</artifactId>
   <version>1.3.2</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

数据库为传统的用户--角色--权限,权限表记录了 url 和 method,springboot 配置文件如下:

mybatis:
  type-aliases-package: com.example.demo.entity
server:
  port: 8081
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true
    username: root
    password: 123456
  http:
    encoding:
      charset: utf-8
      enabled: true

springboot 启动类中加入如下代码,设置路由匹配规则。

@Override
protected void configurePathMatch(PathMatchConfigurer configurer) {
    configurer.setUseSuffixPatternMatch(false) //设置路由是否后缀匹配,譬如/user能够匹配/user.,/user.aa
        .setUseTrailingSlashMatch(false); //设置是否后缀路径匹配,比如/user能够匹配/user,/user/
}

三、 security 配置

??默认情况下 security 是无需任何自定义配置就可使用的,我们不考虑这种方式,直接讲如何个性化登录过程。

1、 建立 security 配置文件,目前配置文件中还没有任何配置。

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}

2、 个性化登录,security 中的登录如下:

  • security 需要一个 user 的实体类实现UserDetails接口,该实体类最后与系统中用户的实体类分开,代码如下:
public class SecurityUser implements UserDetails{
    private static final long serialVersionUID = 1L;
    private String password;
    private String name;
    List<GrantedAuthority> authorities;

    public SecurityUser(string name,string password) {
        this.id = id;
        this.password = password;
        this.name = name;
        this.age = age;
    }

    public void setAuthorities(List<GrantedAuthority> authorities) {
        this.authorities = authorities;
    }

    @Override
    public Collection<GrantedAuthority> getAuthorities() {
        return this.authorities;
    }

    @Override //获取校验用户名
    public String getUsername() {
        return String.valueOf(this.id);
    }

    @Override //获取校验用密码
    public String getPassword() {
        return password;
    }

    @Override //账户是否未过期
    public boolean isAccountNonExpired() {
        // TODO Auto-generated method stub
        return true;
    }

    @Override  //账户是否未锁定
    public boolean isAccountNonLocked() {
        // TODO Auto-generated method stub
        return true;
    }

    @Override  //帐户密码是否未过期,一般有的密码要求性高的系统会使用到,比较每隔一段时间就要求用户重置密码
    public boolean isCredentialsNonExpired() {
        // TODO Auto-generated method stub
        return true;
    }

    @Override //账户是否可用
    public boolean isEnabled() {
        // TODO Auto-generated method stub
        return true;
    }
}
  • 编写了实体类还需要编写一个服务类 SecurityService 实现UserDetailsService接口,重写 loadByUsername 方法,通过这个方法根据用户名获取用户信息,代码如下:
@Component
public class SecurityUserService implements UserDetailsService {
    @Autowired
    private JurisdictionMapper jurisdictionMapper;
    @Autowired
    private UserMapper userMapper;
    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        log.info("登录用户id为:{}",username);
        int id = Integer.valueOf(username);
        User user = userMapper.getById(id);
        if(user==null) {
            //抛出错误,用户不存在
            throw new UsernameNotFoundException("用户名 "+username+"不存在");
        }
        //获取用户权限
        List<GrantedAuthority> authorities = new ArrayList<>();
        List<Jurisdiction> jurisdictions = jurisdictionMapper.selectByUserId(id);
        for(Jurisdiction item : jurisdictions) {
            GrantedAuthority authority = new MyGrantedAuthority(item.getMethod(),item.getUrl());
            authorities.add(authority);
        }
        SecurityUser securityUser = new SecurityUser(user.getName(),user.getPassword(),authority):
        user.setAuthorities(authorities);
        return securityUser;
    }
}
  • 通常我们会对密码进行加密,所有还要编写一个 passwordencode 类,实现 PasswordEncoder 接口,代码如下:
@Component
public class MyPasswordEncoder implements PasswordEncoder {
    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Override //不清楚除了在下面方法用到还有什么用处
    public String encode(CharSequence rawPassword) {
        return StringUtil.StringToMD5(rawPassword.toString());
    }

    //判断密码是否匹配
    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        return encodedPassword.equals(this.encode(rawPassword));
    }
}

3、 编辑配置文件

  • 编写 config Bean 以使用上面定义的验证逻辑,securityUserService、myPasswordEncoder 通过@Autowired 引入。
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(securityUserService)
        .passwordEncoder(myPasswordEncoder);
}
  • 然后编写 configure Bean(和上一个不一样,参数不同),实现 security 验证逻辑,代码如下:
@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .csrf() //跨站
        .disable() //关闭跨站检测
        .authorizeRequests()//验证策略策略链
            .antMatchers("/public/**").permitAll()//无需验证路径
           .antMatchers("/login").permitAll()//放行登录
            .antMatchers(HttpMethod.GET, "/user").hasAuthority("getAllUser")//拥有权限才可访问
            .antMatchers(HttpMethod.GET, "/user").hasAnyAuthority("1","2")//拥有任一权限即可访问
            //角色类似,hasRole(),hasAnyRole()
            .anyRequest().authenticated()
        .and()
        .formLogin()
            .loginPage("/public/unlogin") //未登录跳转页面,设置了authenticationentrypoint后无需设置未登录跳转页面
            .loginProcessingUrl("/public/login")//处理登录post请求接口,无需自己实现
            .successForwardUrl("/success")//登录成功转发接口
            .failureForwardUrl("/failed")//登录失败转发接口
            .usernameParameter("id") //修改用户名的表单name,默认为username
            .passwordParameter("password")//修改密码的表单name,默认为password
        .and()
        .logout()//自定义登出
            .logoutUrl("/public/logout") //自定义登出api,无需自己实现
            .logoutSuccessUrl("public/logoutSuccess")
    }

到这里便可实现 security 与 springboot 的基本整合。

四、实现记住我功能

1、 建表

??记住我功能需要数据库配合实现,首先要在数据库建一张表用户保存 cookie 和用户名,数据库建表语句如下:不能做修改

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`)
)

2、 编写 rememberMeservice Bean

??代码如下:

    @Bean
    public RememberMeServices rememberMeServices(){
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        PersistentTokenBasedRememberMeServices rememberMeServices =
                new PersistentTokenBasedRememberMeServices("INTERNAL_SECRET_KEY",securityUserService,jdbcTokenRepository);
        //还可设置许多其他属性
       rememberMeServices.setCookieName("kkkkk"); //客户端cookie名
        return rememberMeServices;
    }

dataSource 为@Autowired 引入

3、 配置文件设置 remember

??在 config(HttpSecurity http)中加入记住我功能

.rememberMe()
    .rememberMeServices(rememberMeServices())
    .key("INTERNAL_SECRET_KEY")

在登录表单中设置 remember-me 即可实现记住我功能。

本文原创发布于:https://www.tapme.top/blog/detail/2018-08-20-10-38

原文地址:https://www.cnblogs.com/wuyoucao/p/10863419.html

时间: 2024-10-07 22:35:09

springboot+security整合(1)的相关文章

Spring Security整合JWT,实现单点登录,So Easy~!

前面整理过一篇 SpringBoot Security前后端分离,登录退出等返回json数据,也就是用Spring Security,基于SpringBoot2.1.4 RELEASE前后端分离的情况下,实现了登陆登出的功能,亮点就在于以JSON的形式接收返回参数.这个是针对单个后台服务的, 登录信息都存储在SecurityContextHolder缓存里.如果是两个或两个以上的应用呢,那该怎么办?Session是不能用了,Cookie自然也不能用,毕竟它俩是一对的. 曾想过用OAuth2来解决

SpringBoot Kafka 整合实例教程

1.使用IDEA新建工程引导方式,创建消息生产工程 springboot-kafka-producer. 工程POM文件代码如下: 1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instanc

springBoot+SpringData 整合入门

SpringData概述 SpringData :Spring的一个子项目.用于简化数据库访问,支持NoSQL和关系数据存储.其主要目标是使用数据库的访问变得方便快捷. SpringData 项目所支持NoSQL存储: MongoDB(文档数据库) Neo4j(图形数据库) Redis(键/值存储) Hbase(列族数据库) SpringData 项目所支持的关系数据存储技术: JDBC JPA Spring Data : 致力于减少数据访问层 (DAO) 的开发量. 开发者唯一要做的,就只是声

SpringBoot Kafka 整合使用

前提 假设你了解过 SpringBoot 和 Kafka. 1.SpringBoot 如果对 SpringBoot 不了解的话,建议去看看 DD 大佬 和 纯洁的微笑 的系列博客. 2.Kafka Kafka 的话可以看看我前两天写的博客 : Kafka 安装及快速入门 学习的话自己开台虚拟机自己手动搭建环境吧,有条件的买服务器. 注意:一定要亲自自己安装实践,接下来我们将这两个进行整合. 创建项目 项目整体架构: 使用 IDEA 创建 SpringBoot 项目,这个很简单了,这里不做过多的讲

SpringBoot与整合其他技术

SpringBoot与整合其他技术 5.1 SpringBoot整合Mybatis 5.1.1 添加Mybatis的起步依赖 <!--mybatis起步依赖--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</ver

springboot security

什么是springboot security Spring Security是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型.他可以实现强大的web安全控制.对于安全控制, 我们仅需引入spring-boot-starter-security模块,进行少量的配置,即可实现强大的安全管理. 工作流程 WebSecurityConfigurerAdapter:自定义Security策略 AuthenticationManagerBuilder:自定义认证策略 @

Springboot+Activemq整合

Springboot+Activemq整合 1 导入整合所需要的依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-activemq</artifactId> </dependency> 2 创建 application.properties文件 spring.activemq.broker-url=t

SpringBoot学习(二)—— springboot快速整合使用spring security组

Spring Security 简介 spring security的核心功能为认证(Authentication),授权(Authorization),即认证用户是否能访问该系统,和授权用户可以在系统中进行哪些操作. 引入spring security组件 在 pom.xml 中加入 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starte

Spring Security 整合JWT(四)

一.前言 本篇文章将讲述Spring Security 简单整合JWT 处理认证授权 基本环境 spring-boot 2.1.8 mybatis-plus 2.2.0 mysql 数据库 maven项目 Spring Security入门学习可参考之前文章: SpringBoot集成Spring Security入门体验(一)https://blog.csdn.net/qq_38225558/article/details/101754743 Spring Security 自定义登录认证(二