Spring Security实现用户名密码登录详解

目录
  • 环境
  • 用户名密码登录
    • E-R图
    • POM依赖
    • 配置文件
    • Mapper
    • Service设计
    • HTML
    • Controller
    • 启动
  • 完整代码

环境

JDK 1.8

Spring Boot 2.3.0.RELEASE

Maven 3.6.1

H2 数据库

用户名密码登录

首先,我们用 Spring Security 实现用户输入用户名密码登录验证并获取相应权限。

E-R图

完整建表语句

因为是测试程序,所以用H2数据库来测试。SQL脚本在resouces/db目录下,项目启动后会自动初始化脚本,无需手动执行。

schema.sql

DROP TABLE IF EXISTS `SYS_ROLE`;
DROP TABLE IF EXISTS `SYS_USER_ROLE`;
DROP TABLE IF EXISTS `SYS_USER`;

create table SYS_ROLE
(
    ID   INT not null primary key,
    NAME VARCHAR(255) not null
);

create table SYS_USER
(
    ID       INT not null primary key,
    NAME     VARCHAR not null,
    PASSWORD VARCHAR(255) not null
);

create table SYS_USER_ROLE
(
    USER_ID INT not null,
    ROLE_ID INT not null,
    constraint pk_1 primary key (ROLE_ID, USER_ID),
    constraint fk_1 foreign key (ROLE_ID) references SYS_ROLE (ID) on update cascade on delete cascade,
    constraint fk_2 foreign key (USER_ID) references SYS_USER (ID) on update cascade on delete cascade
);

data.sql

INSERT INTO `SYS_ROLE` (`ID`, `NAME`) VALUES (1, 'ADMIN'),(2, 'USER');
INSERT INTO `SYS_USER` (`ID`, `NAME`, `PASSWORD`) VALUES (1, 'super', '888888'), (2, 'jack', '666666'), (3, 'lucy', '999999');
INSERT INTO `SYS_USER_ROLE` (`USER_ID`, `ROLE_ID`) VALUES (1, 1),(2, 2),(3, 2);

准备好建表语句后,完成实体类的编写

SysRole.java

package org.hui.login.model;

/**
 * 用户角色
 * @author zenghui
 * @date 2020-05-20
 */
public class SysRole {
    private Integer id;
    private String name;

    public Integer getId() {return id;}
    public void setId(Integer id) {this.id = id;}
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
}

SysUser.java

package org.hui.login.model;

/**
 * 用户基本信息
 * @author zenghui
 * @date 2020-05-20
 */
public class SysUser  {
    private Integer id;
    private String name;
    private String password;

    public Integer getId() {return id;}
    public void setId(Integer id) {this.id = id;}
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public String getPassword() {return password;}
    public void setPassword(String password) {this.password = password;}
}

SysUserRole.java

package org.hui.login.model;

/**
 * 角色和用户对应关系
 * @author zenghui
 * @date 2020-05-20
 */
public class SysUserRole  {
    private Integer userId;
    private Integer roleId;

    public Integer getUserId() {return userId;}
    public void setUserId(Integer userId) {this.userId = userId;}
    public Integer getRoleId() {return roleId;}
    public void setRoleId(Integer roleId) {this.roleId = roleId;}
}

以上,完成了数据层的设计。

POM依赖

<?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>
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.3.0.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
 </parent>
 <groupId>example</groupId>
 <artifactId>spring-login</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <name>spring-login</name>
 <description>Spring Security to implements Login</description>

 <properties>
  <java.version>1.8</java.version>
 </properties>
 <dependencies>
  <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>2.1.2</version>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
   <groupId>com.h2database</groupId>
   <artifactId>h2</artifactId>
   <scope>runtime</scope>
  </dependency>
 </dependencies>

 <build>
  <plugins>
   <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
   </plugin>
  </plugins>
 </build>

</project>

配置文件

application.properties

spring.datasource.url=jdbc:h2:mem:userdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=123
#设置SQL脚本的位置,resources/db目录下,如果不设置的话,默认就在resources目录下
spring.datasource.schema=classpath:db/schema.sql
spring.datasource.data=classpath:db/data.sql
#H2控制台启用
spring.h2.console.enabled=true
#访问H2的URL
spring.h2.console.path=/h2

# 下划线转化为驼峰命名
mybatis.configuration.map-underscore-to-camel-case=true

Mapper

采用了Mybatis来操作数据库。

准备好需要的几个Mapper,如下

SysRoleMapper.java

package org.hui.login.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.hui.login.model.SysRole;
/**
 * @author zenghui
 * @date 2020-05-20
 */
@Mapper
public interface SysRoleMapper {
    @Select("SELECT * FROM sys_role WHERE id = #{id}")
    SysRole selectById(Integer id);
}

SysUserMapper.java

package org.hui.login.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.hui.login.model.SysUser;
/**
 * @author zenghui
 * @date 2020-05-20
 */
@Mapper
public interface SysUserMapper {
    @Select("SELECT * FROM sys_user WHERE name = #{name}")
    SysUser selectByName(String name);
}

SysUserRoleMapper.java

package org.hui.login.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.hui.login.model.SysUserRole;

import java.util.List;
/**
 * @author zenghui
 * @date 2020-05-20
 */
@Mapper
public interface SysUserRoleMapper {
    @Select("SELECT * FROM sys_user_role WHERE user_id = #{userId}")
    List<SysUserRole> listByUserId(Integer userId);
}

Service设计

Spring Security提供了一个UserDetailsService接口,我们需要实现这个接口的loadUserByUsername方法,用于用户信息的获取,如果存在用户,则把用户的密码获取出来,如果不存在这个用户,直接抛异常。

我们新建一个SysUserDetailService.java

package org.hui.login.service;

import org.hui.login.mapper.SysRoleMapper;
import org.hui.login.mapper.SysUserMapper;
import org.hui.login.mapper.SysUserRoleMapper;
import org.hui.login.model.SysRole;
import org.hui.login.model.SysUser;
import org.hui.login.model.SysUserRole;
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 java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @author zenghui
 * @date 2020-05-20
 */
@Service
public class SysUserDetailService implements UserDetailsService {
    private final SysUserMapper sysUserMapper;
    private final SysRoleMapper sysRoleMapper;
    private final SysUserRoleMapper sysUserRoleMapper;
    public SysUserDetailService(SysUserMapper sysUserMapper, SysRoleMapper sysRoleMapper, SysUserRoleMapper sysUserRoleMapper) {
        this.sysUserMapper = sysUserMapper;
        this.sysRoleMapper = sysRoleMapper;
        this.sysUserRoleMapper = sysUserRoleMapper;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        Collection<GrantedAuthority> authorities = new ArrayList<>();
        // 从数据库中取出用户信息
        SysUser user = sysUserMapper.selectByName(username);

        // 判断用户是否存在
        if(user == null) {
            throw new UsernameNotFoundException("用户名不存在");
        }

        // 添加权限
        List<SysUserRole> userRoles = sysUserRoleMapper.listByUserId(user.getId());
        for (SysUserRole userRole : userRoles) {
            SysRole role = sysRoleMapper.selectById(userRole.getRoleId());
            authorities.add(new SimpleGrantedAuthority(role.getName()));
        }

        // 返回UserDetails实现类
        return new User(user.getName(), user.getPassword(), authorities);

    }
}

如果用户存在,则会进行密码的校验,方便起见,密码我们假设储存为明文,实际上密码有很多加密的策略,这个后序可以自己配置,密码校验在SecurityConfig这个类中,代码如下:

package org.hui.login.config;

import org.hui.login.service.SysUserDetailService;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author zenghui
 * @date 2020-05-20
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private final SysUserDetailService sysUserDetailService;

    public SecurityConfig(SysUserDetailService sysUserDetailService) {
        this.sysUserDetailService = sysUserDetailService;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(sysUserDetailService).passwordEncoder(new PasswordEncoder() {
            @Override
            public String encode(CharSequence charSequence) {
                return charSequence.toString();
            }
            @Override
            public boolean matches(CharSequence charSequence, String s) {
                return s.equals(charSequence.toString());
            }
        });
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated()
                .and().formLogin().loginPage("/login").defaultSuccessUrl("/").permitAll()
                .and().logout().permitAll();

        // 关闭CSRF跨域
        http.csrf().disable();
    }

    @Override
    public void configure(WebSecurity web)  {
        web.ignoring().antMatchers("/css/**", "/js/**");
    }
}

以上便完成了所有后端代码的编写,接下来,完成controller和前端页面的编写。

HTML

在resources的static目录下,新建两个html文件

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页</title>
</head>
<body>
<form action="/login" method="post">
    用户名:<input type="text" name="username">
    密码:<input type="password" name="password">
    <button type="submit">登录</button>
</form>
</body>
</html>

home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主页</title>
</head>
<body>
  登录成功
</body>
</html>

Controller

新建一个LoginController,用于接收前端请求

package org.hui.login.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @author zenghui
 * @date 2020-05-20
 */
@Controller
public class LoginController {
    @RequestMapping("/")
    public String home() {
        return "home.html";
    }
    @RequestMapping("/login")
    public String login() {
        return "login.html";
    }
}

启动

运行以下主程序

package org.hui.login;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author zenghui
 * @date 2020-05-20
 */
@SpringBootApplication
public class LoginApplication {
    public static void main(String[] args) {
        SpringApplication.run(LoginApplication.class, args);
    }
}

访问 http://localhost:8080/login

显示登录页面,输入用户名密码,点击登录,即可看到效果。

完整代码

Github

Gitee

以上就是Spring Security实现用户名密码登录详解的详细内容,更多关于Spring Security用户名密码登录的资料请关注我们其它相关文章!

(0)

相关推荐

  • SpringSecurity自定义登录界面

    为什么需要自定义登录界面? 答:因为SpringBoot整合SpringSecurity时,只需要一个依赖,无需其他配置,就可以实现认证功能.但是它的认证登录界面是固定那样的,如下图所示,但是我们希望自己搞个好看的登录界面,所以需要自定义登录界面. 第一步:创建springboot项目 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.or

  • springSecurity实现简单的登录功能

    前言 1.不使用数据库,实现一个简单的登录功能,只有在登录后才能访问我们的接口2.springSecurity提供了一种基于内存的验证方法(使用自己定义的用户,不使用默认的) 一.实现用户创建,登陆后才能访问接口(注重用户认证) 1.定义一个内存用户,不使用默认用户 重写configure(AuthenticationManagerBuilder auth)方法,实现在内存中定义一个 (用户名/密码/权限:admin/123456/admin) 的用户 package com.example.s

  • Spring Security 实现用户名密码登录流程源码详解

    目录 引言 探究 登录流程 校验 用户信息保存 引言 你在服务端的安全管理使用了 Spring Security,用户登录成功之后,Spring Security 帮你把用户信息保存在 Session 里,但是具体保存在哪里,要是不深究你可能就不知道, 这带来了一个问题,如果用户在前端操作修改了当前用户信息,在不重新登录的情况下,如何获取到最新的用户信息? 探究 无处不在的 Authentication 玩过 Spring Security 的小伙伴都知道,在 Spring Security 中

  • Spring Security实现用户名密码登录详解

    目录 环境 用户名密码登录 E-R图 POM依赖 配置文件 Mapper Service设计 HTML Controller 启动 完整代码 环境 JDK 1.8 Spring Boot 2.3.0.RELEASE Maven 3.6.1 H2 数据库 用户名密码登录 首先,我们用 Spring Security 实现用户输入用户名密码登录验证并获取相应权限. E-R图 完整建表语句 因为是测试程序,所以用H2数据库来测试.SQL脚本在resouces/db目录下,项目启动后会自动初始化脚本,无

  • Spring Security保护用户密码常用方法详解

    1. 前言 本节将对 Spring Security 中的密码编码进行一些探讨. 2. 不推荐使用md5 首先md5 不是加密算法,是哈希摘要.以前通常使用其作为密码哈希来保护密码.由于彩虹表的出现,md5 和sha1之类的摘要算法都已经不安全了.如果有不相信的同学 可以到一些解密网站 如 cmd5 网站尝试解密 你会发现 md5 和 sha1 是真的非常容易被破解. 3. Spring Security中的密码算法 ObjectProvider<PasswordEncoder>参数.这里的P

  • Spring Security短信验证码实现详解

    目录 需求 实现步骤 获取短信验证码 短信验证码校验过滤器 短信验证码登录认证 配置类进行综合组装 需求 输入手机号码,点击获取按钮,服务端接受请求发送短信 用户输入验证码点击登录 手机号码必须属于系统的注册用户,并且唯一 手机号与验证码正确性及其关系必须经过校验 登录后用户具有手机号对应的用户的角色及权限 实现步骤 获取短信验证码 短信验证码校验过滤器 短信验证码登录认证过滤器 综合配置 获取短信验证码 在这一步我们需要写一个controller接收用户的获取验证码请求.注意:一定要为"/sm

  • Spring Security短信验证码实现详解

    目录 需求 实现步骤 获取短信验证码 短信验证码校验过滤器 短信验证码登录认证 配置类进行综合组装 需求 输入手机号码,点击获取按钮,服务端接受请求发送短信 用户输入验证码点击登录 手机号码必须属于系统的注册用户,并且唯一 手机号与验证码正确性及其关系必须经过校验 登录后用户具有手机号对应的用户的角色及权限 实现步骤 获取短信验证码 短信验证码校验过滤器 短信验证码登录认证过滤器 综合配置 获取短信验证码 在这一步我们需要写一个controller接收用户的获取验证码请求.注意:一定要为"/sm

  • Spring Security认证器实现过程详解

    目录 拦截请求 验证过程 返回完整的Authentication 收尾工作 结论 一些权限框架一般都包含认证器和决策器,前者处理登陆验证,后者处理访问资源的控制 Spring Security的登陆请求处理如图 下面来分析一下是怎么实现认证器的 拦截请求 首先登陆请求会被UsernamePasswordAuthenticationFilter拦截,这个过滤器看名字就知道是一个拦截用户名密码的拦截器 主要的验证是在attemptAuthentication()方法里,他会去获取在请求中的用户名密码

  • Spring Security实现分布式系统授权方案详解

    目录 1 需求分析 2 注册中心 3 网关 3.1 创建工程 3.2 token配置 3.3 配置资源服务 3.4 安全配置 4 转发明文token给微服务 5 微服务用户鉴权拦截 6 集成测试 7 扩展用户信息 7.1 需求分析 7.2 修改UserDetailService 7.3 修改资源服务过虑器 1 需求分析 回顾技术方案如下: 1.UAA认证服务负责认证授权. 2.所有请求经过 网关到达微服务 3.网关负责鉴权客户端以及请求转发 4.网关将token解析后传给微服务,微服务进行授权.

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

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

  • Spring Security自定义认证逻辑实例详解

    目录 前言 分析问题 自定义 Authentication 自定义 Filter 自定义 Provider 自定义认证成功/失败后的 Handler 配置自定义认证的逻辑 测试 总结 前言 这篇文章的内容基于对Spring Security 认证流程的理解,如果你不了解,可以读一下这篇文章:Spring Security 认证流程 . 分析问题 以下是 Spring Security 内置的用户名/密码认证的流程图,我们可以从这里入手: 根据上图,我们可以照猫画虎,自定义一个认证流程,比如手机短

  • Spring Security认证提供程序示例详解

    1.简介 本教程将介绍如何在Spring Security中设置身份验证提供程序,与使用简单UserDetailsService的标准方案相比,提供了额外的灵活性. 2. The Authentication Provider Spring Security提供了多种执行身份验证的选项 - 所有这些都遵循简单的规范 - 身份验证请求由Authentication Provider处理,并且返回具有完整凭据的完全身份验证的对象. 标准和最常见的实现是DaoAuthenticationProvide

随机推荐