zl程序教程

您现在的位置是:首页 >  后端

当前栏目

Spring Security

Spring Security
2023-06-13 09:13:09 时间

# 简介

身份验证和访问控制的框架

  1. 扩展度高
  2. 对比shiro

spring security

shiro

配置复杂

社区支持好

boot项目用

spring mvc用

跨平台,可以独立运行

仅支持spring

# 项目搭建

springBoot 2.5.5 + Mybatis + Spring Security 5.x

Spring Security 5.0+ 变化版本较多,且不兼容之前的版本,确保你的springBoot版本为2.0。

  1. 添加依赖,注意mysql包
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.2</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.27</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

# 模板语法

jsp

thymeleaf

默认开启表单认证,用户名user,密码在控制台输出

# httpBasic认证(不用)

注意添加configuration注解

package com.zr.config;

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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //开启httpBasic认证
        http.httpBasic()
            //每个模块配置使用and结尾
            .and()
            //配置路径拦截,表明路径访问所对应的权限,角色,认证信息
            .authorizeRequests()
            .anyRequest()
            //所有请求都需要登录认证才能访问
            .authenticated();
    }
}

# 自定义账户密码

修改yaml配置文件

spring:
  security:
    user:
      name: px
      password: 1234

# 表单认证

添加配置类,可以修改用户密码字段名,与前端对应上。

package com.zr.config;

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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login.html","/login")
                .permitAll()
                .anyRequest()
                .authenticated()
                .and()
                .formLogin()
                .loginPage("/login.html")
                .loginProcessingUrl("/login")
                .usernameParameter("userId")
                .passwordParameter("password")
                .defaultSuccessUrl("/home");
        //关闭跨域攻击防护
        http.csrf().disable();
    }
}

# 权限认证

配置权限 PasswordEncoder接口,常用BCryptPasswordEncoder实现类

http.authorizeRequests()
    .antMatchers("/login.html","/login")
    .permitAll()
    .antMatchers("/user","/role")
    .hasAnyAuthority("ROLE_user","ROLE_admin")
    .antMatchers("/auth","/others")
    .hasAnyAuthority("ROLE_admin")
    .anyRequest()
    .authenticated()
    .and()
    .formLogin()
    .loginPage("/login.html")
    .loginProcessingUrl("/login")
    .usernameParameter("username")
    .passwordParameter("password")
    .defaultSuccessUrl("/home");
//关闭跨域攻击防护
http.csrf().disable();

密码加密,有盐值,需要用matches方法判断密码是否匹配

package com.zr;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.security.crypto.password.PasswordEncoder;

@SpringBootTest
public class SecurityTest {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Test
    public void testPassword(){
        String pwd1 = passwordEncoder.encode("1234");
        String pwd2 = passwordEncoder.encode("1234");
        System.out.println("加密字符串[1234]"+pwd1);
        System.out.println("加密字符串[1234]"+pwd2);
        System.out.println("判断pwd1是否为[1234]"+passwordEncoder.matches("1234",pwd1));
        System.out.println("判断pwd1是否为[1234]"+passwordEncoder.matches("1234",pwd2));
        System.out.println("盐值"+BCrypt.gensalt());
        System.out.println("盐值"+BCrypt.gensalt());
    }
}

内存中创建用户角色

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    //内存中配置用户和角色信息
    auth.inMemoryAuthentication()
        //设置用户
        .withUser("px")
        //设置密码
        .password(passwordEncoder.encode("1234"))
        //设置角色,注意:角色缺省ROLE_
        .roles("user")
        .and()
        .withUser("admin")
        .password(passwordEncoder.encode("1234"))
        .roles("admin")
        .and()
        //设置密码加密算法
        .passwordEncoder(passwordEncoder);
}

数据库

DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
  `user_id` varchar(32) NOT NULL COMMENT '账号',
  `user_name` varchar(32) NOT NULL COMMENT '用户名',
  `user_type` varchar(2) DEFAULT NULL COMMENT '用户类型(00系统用户)',
  `email` varchar(50) DEFAULT NULL COMMENT '用户邮箱',
  `phonenumber` varchar(11) DEFAULT NULL COMMENT '手机号码',
  `sex` char(1) DEFAULT NULL COMMENT '用户性别(0女 1男 2未知)',
  `avatar` varchar(200) DEFAULT NULL COMMENT '头像地址',
  `password` varchar(100) DEFAULT NULL COMMENT '用户密码',
  `last_login_time` datetime DEFAULT NULL COMMENT '上一次登录时间',
  `last_login_ip` varchar(128) DEFAULT NULL COMMENT '上一次登录地址',
  `enabled` tinyint(1) DEFAULT '1' COMMENT '账号是否可用。默认为1(可用)',
  `not_expired` tinyint(1) DEFAULT '1' COMMENT '是否过期。默认为1(没有过期)',
  `account_not_locked` tinyint(1) DEFAULT '1' COMMENT '账号是否锁定。默认为1(没有锁定)',
  `credentials_not_expired` tinyint(1) DEFAULT '1' COMMENT '证书(密码)是否过期。默认为1(没有过期)',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '修改时间',
  `create_user` varchar(32) DEFAULT NULL COMMENT '创建人',
  `update_user` varchar(32) DEFAULT NULL COMMENT '修改人',
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';

DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
  `role_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `role_name` varchar(32) DEFAULT NULL COMMENT '角色名',
  `role_sort` int(11) DEFAULT NULL COMMENT '显示顺序',
  `role_remark` varchar(64) DEFAULT NULL COMMENT '角色说明',
  PRIMARY KEY (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色表';

DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
  `user_id` varchar(32) DEFAULT NULL,
  `role_id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `sys_auth`;
CREATE TABLE `sys_auth` (
  `auth_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '权限ID',
  `auth_name` varchar(50) NOT NULL COMMENT '权限(菜单)名称',
  `parent_id` int(11) DEFAULT '0' COMMENT '父菜单ID',
  `auth_sort` int(4) DEFAULT '0' COMMENT '显示顺序',
  `path` varchar(200) DEFAULT '' COMMENT '路由地址',
  `component` varchar(255) DEFAULT NULL COMMENT '组件路径',
  `query` varchar(255) DEFAULT NULL COMMENT '路由参数',
  `auth_type` char(1) DEFAULT '' COMMENT '权限(菜单)类型(M目录 C菜单 F按钮)',
  `visible` char(1) DEFAULT '0' COMMENT '菜单状态(0隐藏 1显示)',
  `perms` varchar(100) DEFAULT NULL COMMENT '权限标识',
  `icon` varchar(100) DEFAULT '#' COMMENT '菜单图标',
  `status` char(1) DEFAULT '0' COMMENT '菜单状态(0正常 1停用)',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `create_user` varchar(32) DEFAULT '' COMMENT '创建人',
  `update_user` varchar(32) DEFAULT '' COMMENT '修改人',
  `remark` varchar(500) DEFAULT '' COMMENT '备注',
  PRIMARY KEY (`auth_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1067 DEFAULT CHARSET=utf8 COMMENT='菜单权限表';

DROP TABLE IF EXISTS `sys_role_auth`;
CREATE TABLE `sys_role_auth` (
  `role_id` int(11) DEFAULT NULL COMMENT '角色ID',
  `auth_id` int(11) DEFAULT NULL COMMENT '权限ID'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

添加数据

INSERT INTO `sys_user` (`user_id`, `user_name`, `user_type`, `email`, `phonenumber`, `sex`, `avatar`, `password`, `last_login_time`, `last_login_ip`, `enabled`, `not_expired`, `account_not_locked`, `credentials_not_expired`, `create_time`, `update_time`, `create_user`, `update_user`) VALUES ('admin', '管理员', '1', NULL, NULL, '男', NULL, '$2a$10$K.QFed/vCaI0pBIoCQ/iP.IPI9tNF4XdnZ53a0n6OJ3bZTcs5iFpO', NULL, NULL, '1', '1', '1', '1', NULL, NULL, NULL, NULL);
INSERT INTO `sys_user` (`user_id`, `user_name`, `user_type`, `email`, `phonenumber`, `sex`, `avatar`, `password`, `last_login_time`, `last_login_ip`, `enabled`, `not_expired`, `account_not_locked`, `credentials_not_expired`, `create_time`, `update_time`, `create_user`, `update_user`) VALUES ('zr', '中软', '1', NULL, NULL, '男', NULL, '$2a$10$Y6M/tp8V2vIe5b7C851ISe568ph8YwK/4cYltURIPRERDINC0IgRK', NULL, NULL, '1', '1', '1', '1', NULL, NULL, NULL, NULL);
INSERT INTO `sys_role` (`role_id`, `role_name`, `role_sort`, `role_remark`) VALUES ('1', '普通用户', '1', 'ROLE_user');
INSERT INTO `sys_role` (`role_id`, `role_name`, `role_sort`, `role_remark`) VALUES ('2', '管理员', '2', 'ROLE_admin');
INSERT INTO `sys_user_role` (`user_id`, `role_id`) VALUES ('zr', '1');
INSERT INTO `sys_user_role` (`user_id`, `role_id`) VALUES ('admin', '2');
INSERT INTO `sys_auth` (`auth_id`, `auth_name`, `parent_id`, `auth_sort`, `path`, `component`, `query`, `auth_type`, `visible`, `perms`, `icon`, `status`, `create_time`, `update_time`, `create_user`, `update_user`, `remark`) VALUES ('1', '用户管理', NULL, '1', '', NULL, NULL, 'C', '0', NULL, '#', '0', NULL, NULL, '', '', '');
INSERT INTO `sys_auth` (`auth_id`, `auth_name`, `parent_id`, `auth_sort`, `path`, `component`, `query`, `auth_type`, `visible`, `perms`, `icon`, `status`, `create_time`, `update_time`, `create_user`, `update_user`, `remark`) VALUES ('2', '角色管理', NULL, '2', '', NULL, NULL, 'C', '0', NULL, '#', '0', NULL, NULL, '', '', '');
INSERT INTO `sys_auth` (`auth_id`, `auth_name`, `parent_id`, `auth_sort`, `path`, `component`, `query`, `auth_type`, `visible`, `perms`, `icon`, `status`, `create_time`, `update_time`, `create_user`, `update_user`, `remark`) VALUES ('3', '权限管理', NULL, '3', '', NULL, NULL, 'C', '0', NULL, '#', '0', NULL, NULL, '', '', '');
INSERT INTO `sys_auth` (`auth_id`, `auth_name`, `parent_id`, `auth_sort`, `path`, `component`, `query`, `auth_type`, `visible`, `perms`, `icon`, `status`, `create_time`, `update_time`, `create_user`, `update_user`, `remark`) VALUES ('4', '其它管理', NULL, '4', '', NULL, NULL, 'C', '0', NULL, '#', '0', NULL, NULL, '', '', '');
INSERT INTO `sys_auth` (`auth_id`, `auth_name`, `parent_id`, `auth_sort`, `path`, `component`, `query`, `auth_type`, `visible`, `perms`, `icon`, `status`, `create_time`, `update_time`, `create_user`, `update_user`, `remark`) VALUES ('5', '用户查询', '1', '1', '', NULL, NULL, 'F', '0', 'sys:user:list', '#', '0', NULL, NULL, '', '', '');
INSERT INTO `sys_auth` (`auth_id`, `auth_name`, `parent_id`, `auth_sort`, `path`, `component`, `query`, `auth_type`, `visible`, `perms`, `icon`, `status`, `create_time`, `update_time`, `create_user`, `update_user`, `remark`) VALUES ('6', '用户新增', '1', '2', '', NULL, NULL, 'F', '0', 'sys:user:add', '#', '0', NULL, NULL, '', '', '');
INSERT INTO `sys_role_auth` (`role_id`, `auth_id`) VALUES ('1', '1');
INSERT INTO `sys_role_auth` (`role_id`, `auth_id`) VALUES ('1', '2');
INSERT INTO `sys_role_auth` (`role_id`, `auth_id`) VALUES ('1', '5');

反向生成mapper

通过数据库设置角色

package com.zr.service.security.impl;

import com.zr.mapper.sys.SysRoleMapper;
import com.zr.mapper.sys.SysUserMapper;
import com.zr.vo.sys.SysRole;
import com.zr.vo.sys.SysUser;
import org.springframework.context.annotation.Primary;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service
@Primary
public class UserDetailsServiceImpl implements UserDetailsService {

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private SysRoleMapper sysRoleMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根据登录账户获取用户信息
        SysUser sysUser= sysUserMapper.selectByPrimaryKey(username);
        if(sysUser == null) throw new UsernameNotFoundException("用户账户不存在");
        List<SysRole> sysRoleList = sysRoleMapper.selectByUserId(username);
        //权限集合
        Set<GrantedAuthority> authorities = new HashSet<>();
        for(SysRole sysRole:sysRoleList){
            authorities.add(new SimpleGrantedAuthority(sysRole.getRoleRemark()));
        }
        return new User(username, sysUser.getPassword(), authorities);
    }
}