Spring Security使用数据库登录认证授权

目录
  • 一、搭建项目环境
    • 1、创建 RBAC五张表
    • 2、创建项目
  • 二、整合 Spring Security实现用户认证
    • 1、后端整合
    • 2、前端整合
  • 三、整合 Spring Security实现用户授权
    • 1、后端
    • 2、前端

一、搭建项目环境

1、创建 RBAC五张表

RBAC,即基于角色的权限访问控制(Role-Based Access Control),就是用户通过角色与权限进行关联。
在这种模型中,用户与角色之间,角色与权限之间,一般者是多对多的关系。

在 MySQL数据库中,创建如下几个表:

DROP TABLE IF EXISTS sys_user;
CREATE TABLE sys_user(
    id BIGINT NOT NULL AUTO_INCREMENT  COMMENT '主键id' ,
    username VARCHAR(60)    COMMENT '用户名' ,
    password VARCHAR(255)    COMMENT '密码' ,
    status tinyint(1)    COMMENT '用户状态,1-开启-0禁用' ,
    password_non_expired tinyint(1)    COMMENT '密码是否失效,1-可用,0-失效' ,
    PRIMARY KEY (id)
)  COMMENT = '用户表';

DROP TABLE IF EXISTS sys_role;
CREATE TABLE sys_role(
    id BIGINT NOT NULL AUTO_INCREMENT  COMMENT '主键id' ,
    role_name VARCHAR(64) NOT NULL   COMMENT '角色名' ,
    role_desc VARCHAR(64) NOT NULL   COMMENT '角色描述' ,
    PRIMARY KEY (id)
)  COMMENT = '角色表';

DROP TABLE IF EXISTS sys_permission;
CREATE TABLE sys_permission(
    id BIGINT NOT NULL AUTO_INCREMENT  COMMENT '主键id' ,
    parent_id BIGINT    COMMENT '父id' ,
    permission_name VARCHAR(64)    COMMENT '菜单名称' ,
    permission_url VARCHAR(255)    COMMENT '菜单地址' ,
    PRIMARY KEY (id)
)  COMMENT = '权限表';

DROP TABLE IF EXISTS sys_user_role;
CREATE TABLE sys_user_role(
    id BIGINT NOT NULL AUTO_INCREMENT  COMMENT '主键id' ,
    user_id BIGINT NOT NULL   COMMENT '用户id' ,
    role_id BIGINT    COMMENT '角色id' ,
    enabled tinyint(1)   DEFAULT 1 COMMENT '是否有效' ,
    PRIMARY KEY (id)
)  COMMENT = '用户角色关联表';

DROP TABLE IF EXISTS sys_role_permission;
CREATE TABLE sys_role_permission(
    id BIGINT NOT NULL AUTO_INCREMENT  COMMENT '主键id' ,
    role_id BIGINT NOT NULL   COMMENT '角色id' ,
    permission_id BIGINT    COMMENT '权限id' ,
    PRIMARY KEY (id)
)  COMMENT = '角色权限表';

2、创建项目

创建 Mavne 项目,Springboot + Spring Security + MyBatis + MySQL + jsp。

1)配置文件如下

server:
  port: 9090

# jsp配置
spring:
  mvc:
    view:
      prefix: /pages/
      suffix: .jsp
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/security_authority?useUnicode=true;characterEncoding=utf8;useSSL=true;serverTimezone=GMT
    username: root
    password: 123456

# mybatis配置
mybatis:
  configuration:
    map-underscore-to-camel-case: true
  mapper-locations: classpath:mybatis/mapper/*.xml

logging:
  level:
    com.charge.learn.springsecurity.springboot.security.jsp.dao: debug

2)启动类

@SpringBootApplication
@MapperScan("com.charge.learn.springsecurity.springboot.security.jsp.dao")
public class SpringSecurityApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringSecurityApplication.class, args);
    }
}

二、整合 Spring Security实现用户认证

1、后端整合

1.1 用户

Spring Security的用户对象是 UserDetail类型,Spring Security在认证流程中只认 UserDetail用户。

  • 通过 UserDetailsService的 loadUserByUsername方法获取 UserDetail用户。
  • 认证成功之后,调用的是这个带有三个参数的 UsernamePasswordAuthenticationToken构造方法,将 角色信息添加到了ArrayList<GrantedAuthority>集合中。
  • 在 successfulAuthentication 方法中,将认证信息存储到了SecurityContext中。

UserDetail接口的方法(根据用户业务来处理这几个值)。

  • boolean enabled 账户是否可用
  • boolean accountNonExpired 账户是否失效
  • boolean credentialsNonExpired 账户密码是否失效
  • boolean accountNonLocked 账户是否锁定
  • Collection<? extends GrantedAuthority> getAuthorities() 获取账户的所有权限(用户角色)

注意:四个布尔类型的参数都为 true时,然后成功,否则,有一个为 false,就会认证失败。

所以,我们可以将我们的用户封装成 UserDetail对象。
这里我们让用户对象实现 UserDetail接口,那么我们用户就属于 UserDetail类型的用户,然后实现接口的方法。

public class SysUser implements UserDetails {

    private Long id;
    private String username;
    private String password;
    private Boolean status; //用户状态,1-开启-0禁用
    private Boolean passwordNonExpired; //密码是否失效,1-可用,0-失效
    /**
     * 用户关联的所有角色
     */
    private List<SysRole> roles = new ArrayList<>();

//get、set方法

    //标记该字段不做json处理
    @JsonIgnore
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return roles;
    }

    @JsonIgnore
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @JsonIgnore
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @JsonIgnore
    @Override
    public boolean isCredentialsNonExpired() {
        return passwordNonExpired == null ? false : passwordNonExpired;
    }

    @JsonIgnore
    @Override
    public boolean isEnabled() {
        return status == null ? false : status;
    }

}

1.2 角色

Spring Security的权限对象是 GrantedAuthority类型。通过它的值来实现权限管理的。

所以,我们让角色对象实现GrantedAuthority接口,那么我们角色就属于 GrantedAuthority类型,然后实现接口的方法。
上面用户可以直接将 角色添加到 Collection<? extends GrantedAuthority>集合中。

public class SysRole implements GrantedAuthority {

    private Long id;
    private String roleName;
    private String roleDesc;

//get、set方法

    //标记该字段不做json处理
    @JsonIgnore
    @Override
    public String getAuthority() {
        return roleName;
    }

}

1.3 SysUserService接受继承UserDetailsService类

Spring Security在认证流程中通过 UserDetailsService的 loadUserByUsername方法获取 UserDetail用户。

所以,我们让 UserService接口继承 UserDetailsService类,然后重写 loadUserByUsername方法。

在 loadUserByUsername方法中,获取我们的用户信息( UserDetail类型),记得将用户关联的角色也赋值为用户信息。

public interface SysUserService extends UserDetailsService {

    void save(SysUser user);
}
@Service
@Transactional
public class SysUserServiceImpl implements SysUserService {

	@Autowired
	private SysUserMapper sysUserMapper;

	@Autowired
	private SysRoleMapper sysRoleMapper;

	@Autowired
	private BCryptPasswordEncoder passwordEncoder;

	@Override
	public void save(SysUser sysUser) {
		// 将密码加密入库
		sysUser.setPassword(passwordEncoder.encode(sysUser.getPassword()));
		sysUserMapper.insert(sysUser);
	}

	/**
	 * 认证业务
	 *
	 * @param username
	 *            - 用户在浏览器输入的用户名
	 * @return UserDetails - Spring Security的用户对象,返回 null表示认证失败!
	 * @throws UsernameNotFoundException
	 */
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		/**
		 * 用户信息和角色信息可以一步关联查询到位得到SysUser,我这里分开查询
		 */
		// 1.查询用户
		SysUser sysUser = sysUserMapper.getByUsername(username);
		if (sysUser == null) {
			return null;
		}
		// 2.获取用户关联的所有角色
		List<SysRole> sysRoles = sysRoleMapper.listAllByUserId(sysUser.getId());
		sysUser.setRoles(sysRoles);
		System.out.println("====> sysUser=" + sysUser.toString());
		return sysUser;
	}
}

mapper.xml中的几个方法

  <select id="getByUsername" resultMap="BaseResultMap">
    select id, username, password, status, password_non_expired from sys_user where username = #{username}
  </select>

  <select id="listAllByUserId" resultMap="BaseResultMap">
    SELECT r.id, r.role_name role_name, r.role_desc role_desc
    FROM sys_role r, sys_user_role ur
    WHERE r.id = ur.role_id AND ur.user_id = #{userId}
  </select>

1.4 创建 SpringSecurity配置类

自定义一个配置类,添加@EnableWebSecurity注解,并继承WebSecurityConfigurerAdapter类。然后就拥有了 SpringSecutiry的所有默认配置。我们也可以修改配置。

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SysUserService userService;

    // 加密对象注入IOC容器
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    // 1.指定认证对象的来源(内存或者数据库),指定加密方式
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
    }

    //2. SpringSecurity配置相关信息
    @Override
    public void configure(HttpSecurity http) throws Exception {
        // 释放静态资源,指定拦截规则,指定自定义的认证和退出页面,csrf配置等
        http.authorizeRequests()
                // 指定拦截规则
                .antMatchers("/login.jsp", "failer.jsp", "/css/**", "/img/**", "/plugins/**").permitAll()  //释放这些资源,不拦截
                .antMatchers("/**").hasAnyRole("USER", "ADMIN") //所有资源都需要这些角色中的一个
                .anyRequest().authenticated()  //其他请求,必须认证通过之后才能访问
                .and()  // 表示新的一个配置开始
                // 指定自定义的认证页面
                .formLogin()
                .loginPage("/login.jsp")
                .loginProcessingUrl("/login")
                .successForwardUrl("/index.jsp")
                .failureForwardUrl("/failer.jsp")
                .permitAll() // 释放这些资源,不拦截登录
                .and()
                // 指定自定义的退出页面
                .logout()
                .logoutSuccessUrl("/logout")
                .invalidateHttpSession(true) // 清楚session
                .logoutSuccessUrl("/login.jsp")
                .permitAll()
                //.and()
//                禁用csrf配置,默认开启的(一般不写,页面要加csrf),这里我们测试下
//                .and()
//                .csrf()
//                .disable()
                ;
    }

主要配置信息如下:

  • 指定认证对象 SysUserService (UserDetailsService类型)
  • 指定了用户密码使用的加密对象
  • SpringSecurity配置相关信息,比如:指定拦截规则,指定自定义的认证页面,csrf等。

2、前端整合

在 Spring Security 中,如果我们不做任何配置,默认的登录页面和登录接口的地址都是 /login,即默认会存在如下两个请求:

  • GET http://localhost:8080/login
  • POST http://localhost:8080/login

如果是 GET 请求表示你想访问登录页面,如果是 POST 请求,表示你想提交登录数据。默认的表单字段为 username和password。

SpringSecurity 默认 是开启 csrf防护机制。
所以,在自定义的表单上添加上 _csrf隐藏input(必须要写在form表单里面)。

引入 security标签库
<%@taglib uri="http://www.springframework.org/security/tags" prefix="security"%>
<security:csrfInput/>

启动项目,登录认证访问ok.

三、整合 Spring Security实现用户授权

认证过程获取用户信息时,我们已经把用户关联的角色信息设置到了 UserDetails中,所以,我们只需要分配 资源访问的角色就可以了。

1、后端

1.1 开启 Spring Security权限控制

Spring Security可以通过注解的方式来控制类或者方法的访问权限。支持开启权限控制的注解类型如下:

  • jsr250-annotations:表示支持 jsr250-api的注解
  • pre-post-annotations:表示支持 spring表达式注解
  • secured-annotations:这才是 Spring Security提供的注解

在实际开发中,用一类即可,三个都开启也没关系。
在 SpringSecurity配置类上 添加 @EnableGlobalMethodSecurity注解,表示开启 Spring Security权限控制,这里我们三类都开启了。

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled=true, prePostEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    ...
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled=true, prePostEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
...

1.2 在角色对应类或者方法上添加权限注解

1.2.1 使用 Spring Security注解

  • @Secured({“ROLE_ADMIN”,“ROLE_PRODUCT”})
@Controller
@RequestMapping("/user")
@Secured("ROLE_ADMIN") 	//表示当前类中所有方法需要 ROLE_ADMIN才能访问
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("/findAll")
    public String findAll(Model model){
        List<SysUser> list = userService.findAll();
        model.addAttribute("list", list);
        return "user-list";
    }
    。。。
 }

1.2.2 使用 Spring表达式注解

  • @PreAuthorize(“hasAnyRole(‘ROLE_ADMIN’,‘ROLE_PRODUCT’)”)
@Controller
@RequestMapping("/product")
public class ProductController {

    @RequestMapping("/findAll")
    //表示当前类中findAll方法需要 ROLE_ADMIN或者 ROLE_PRODUCT才能访问
    @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_PRODUCT')")
    public String findAll(){
        return "product-list";
    }
}

1.2.3 使用 JSR-250注解

  • @RolesAllowed({“ROLE_ADMIN”,“ROLE_User”})
@Controller
@RequestMapping("/order")
@RolesAllowed({"ROLE_ADMIN","ROLE_USER"}) //表示当前类中所有方法都需要ROLE_ADMIN或者ROLE_User才能访问
public class OrderController {

    @RequestMapping("/findAll")
    public String findAll(){
        return "order-list";
    }
}

2、前端

在jsp业页面中,对每个菜单资源通过 SpringSecurity标签库指定访问所需的角色。

<%@taglib uri="http://www.springframework.org/security/tags" prefix="security" %>
<!-- 指定访问所需角色 -->
<security:authorize access="hasAnyRole('ROLE_ADMIN', '等等')">

启动项目,通过不同的用户登录,授权访问ok.

到此这篇关于Spring Security使用数据库登录认证授权的文章就介绍到这了,更多相关Spring Security数据库登录认证授权内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring Security OAuth2认证授权示例详解

    本文介绍了如何使用Spring Security OAuth2构建一个授权服务器来验证用户身份以提供access_token,并使用这个access_token来从资源服务器请求数据. 1.概述 OAuth2是一种授权方法,用于通过HTTP协议提供对受保护资源的访问.首先,OAuth2使第三方应用程序能够获得对HTTP服务的有限访问权限,然后通过资源所有者和HTTP服务之间的批准交互来让第三方应用程序代表资源所有者获取访问权限. 1.1 角色 OAuth定义了四个角色 资源所有者 - 应用程序的

  • Java Spring Security认证与授权及注销和权限控制篇综合解析

    Spring Security简介: Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,它可以实现强大的Web安全控制,对于安全控制,我们只需要引入 spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理! 记住几个类: WebSecurityConfigurerAdapter:自定义Security策略 AuthenticationManagerBuilder:自定义认证策略

  • SpringBoot+SpringSecurity实现基于真实数据的授权认证

    (一)概述 Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架,Spring Security主要做两个事情,认证.授权.我之前写过一篇关于SpringSecurity的博客,但是当时只是介绍了基于mock数据的案例,本期就来介绍一下基于真实数据的认证授权实现. (二)前期项目搭建 为了更好的展示SpringSecurity,我们先搭建一个简单的web项目出来.引入thymeleaf依赖 <dependency> <groupId>org.spring

  • SpringSecurity数据库进行认证和授权的使用

    目录 一.准备工作 1.1 导入相关依赖 1.2 配置信息 1.3 数据库准备 1.4 实体类的创建 1.5 Dao层的创建 1.6 Service层的编写 1.7 Security配置 1.8 密码加密 1.9 测试结果 在前面的文章中,我们介绍了Spring Security基于内存的一些基本使用方法,但在真实的业务场景中,用户的账号.密码以及角色信息肯定都是存放在数据库中的,所以我们需要从数据库中来加载认证和授权的数据. 一.准备工作 如下案例是基于上一篇中的案例改造而来,所以建议先阅读前

  • Spring Security使用数据库登录认证授权

    目录 一.搭建项目环境 1.创建 RBAC五张表 2.创建项目 二.整合 Spring Security实现用户认证 1.后端整合 2.前端整合 三.整合 Spring Security实现用户授权 1.后端 2.前端 一.搭建项目环境 1.创建 RBAC五张表 RBAC,即基于角色的权限访问控制(Role-Based Access Control),就是用户通过角色与权限进行关联.在这种模型中,用户与角色之间,角色与权限之间,一般者是多对多的关系. 在 MySQL数据库中,创建如下几个表: D

  • 详解Spring Security的formLogin登录认证模式

    一.formLogin的应用场景 在本专栏之前的文章中,已经给大家介绍过Spring Security的HttpBasic模式,该模式比较简单,只是进行了通过携带Http的Header进行简单的登录验证,而且没有定制的登录页面,所以使用场景比较窄. 对于一个完整的应用系统,与登录验证相关的页面都是高度定制化的,非常美观而且提供多种登录方式.这就需要Spring Security支持我们自己定制登录页面,也就是本文给大家介绍的formLogin模式登录认证模式. 准备工作 新建一个Spring B

  • Spring Security基于数据库实现认证过程解析

    创建数据库 SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for role -- ---------------------------- DROP TABLE IF EXISTS `role`; CREATE TABLE `role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(32) DEFAULT NULL, `nam

  • Spring Security使用数据库认证及用户密码加密和解密功能

    流程图: 1.接上一篇博客https://mp.csdn.net/console/editor/html/104576494,准备好环境. 2.spring-security.xml中的配置: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:security="

  • Spring Security基于自定义的认证提供器实现图形验证码流程解析

    目录 前言 一. 认证提供器简介 1. 认证提供器AuthenticationProver 2. WebAuthenticationDetails类介绍 二. 实现图形验证码 1. 添加依赖包 2. 创建Producer对象 3. 创建生成验证码的接口 4. 自定义异常 5. 自定义WebAuthenticationDetails 6. 自定义AuthenticationDetailsSource 7. 自定义DaoAuthenticationProver 8. 添加SecurityConfig

  • Spring Security使用单点登录的权限功能

    目录 背景 Spring Security 实现 已经有了单点登录页面,Spring Security怎么登录,不登录可以拿到权限吗 Authentication 继续分析 结论 如何手动登录Spring Security 结论 总结 附 参考 背景 在配置中心增加权限功能 目前配置中心已经包含了单点登录功能,可以通过统一页面进行登录,登录完会将用户写入用户表 RBAC的用户.角色.权限表CRUD.授权等都已经完成 希望不用用户再次登录,就可以使用SpringSecurity的权限控制 Spri

  • Spring Security实现统一登录与权限控制的示例代码

    目录 项目介绍 统一认证中心 配置授权服务器 配置WebSecurity 登录 菜单 鉴权 资源访问的一些配置 有用的文档 项目介绍 最开始是一个单体应用,所有功能模块都写在一个项目里,后来觉得项目越来越大,于是决定把一些功能拆分出去,形成一个一个独立的微服务,于是就有个问题了,登录.退出.权限控制这些东西怎么办呢?总不能每个服务都复制一套吧,最好的方式是将认证与鉴权也单独抽离出来作为公共的服务,业务系统只专心做业务接口开发即可,完全不用理会权限这些与之不相关的东西了.于是,便有了下面的架构图:

  • Spring Security实现验证码登录功能

    这篇文章主要介绍了Spring Security实现验证码登录功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在spring security实现登录注销功能的基础上进行开发. 1.添加生成验证码的控制器. (1).生成验证码 /** * 引入 Security 配置属性类 */ @Autowired private SecurityProperties securityProperties; @Override public ImageC

  • Spring Security OAuth2 实现登录互踢的示例代码

    本文主要介绍了Spring Security OAuth2 实现登录互踢的示例代码,分享给大家,具体如下: 背景说明 一个账号只能一处登录,类似的业务需求在现有后管类系统是非常常见的. 但在原有的 spring security oauth2 令牌方法流程(所谓的登录)无法满足类似的需求. 我们先来看 TokenEndpoint 的方法流程 客户端 带参访问 /oauth/token 接口,最后去调用 TokenGranter TokenGranter 根据不同的授权类型,获取用户认证信息 并去

  • Spring Security实现退出登录和退出处理器

    在系统中一般都有退出登录的操作.退出登录后,Spring Security进行了以下操作: 清除认证状态 销毁HttpSession对象 跳转到登录页面 配置退出登录的路径和退出后跳转的路径 //退出登录配置 http.logout() .logoutUrl("/logout") .logoutSuccessUrl("/login.html") .clearAuthentication(true) .invalidateHttpSession(true); 在网页中

随机推荐