详解使用Spring Security进行自动登录验证

在之前的博客使用SpringMVC创建Web工程并使用SpringSecurity进行权限控制的详细配置方法 中,我们描述了如何配置一个基于SpringMVC、SpringSecurity框架的网站系统。在这篇博客中,我们将继续描述如何使用Spring Security进行登录验证。
总结一下Spring Security的登录验证关键步骤:

1、在数据库中建好三张表,即users、authorities和persistent_logins三个。注意字段的定义,不能少,可以多,名字必须按规定来。

2、在Spring Security的配置文件中,配置好登录跳转的页面,登录处理的页面和加密情况。

3、在前台的jsp页面中,登录的字段必须和后台users表中的一致,一般都是username和password。

4、注册页面必须自己写,注册的处理也要自己写。

一、创建数据表

使用Spring Security进行登录验证,需要我们在数据库中建好相应的表,并且字段要和Spring Security内置的字段一致。主要有3张表需要建立。一是users表,包含用户名和密码以及用户状态的表;第二个是authorities表,表明该用户角色的,方便做角色控制,比如是ROLE_USER还是ROLE_ADMIN(比如admin页面可能需要用户的ROLE_ADMIN权限,而ROLE_USER权限无法登录这个管理页面);最后一个是persistent_logins表,是登录状态的记录表,主要用来提供支持“记住我”功能的。三张表的创建语句如下:

#create users table
CREATE TABLE `users` (
 `username` varchar(100) NOT NULL,
 `password` varchar(100) NOT NULL,
 `enabled` tinyint(1) NOT NULL DEFAULT '1',
 UNIQUE KEY `account` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

#create authorities table
CREATE TABLE `authorities` (
 `username` varchar(50) NOT NULL,
 `authority` varchar(50) DEFAULT NULL,
 PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

#create persistent_logins table
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`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

记住,这三张表字段一定要至少包含以上字段。这样Spring Security才能识别。但是,我们也可以额外添加一些字段,比如在users中添加uid等。

二、配置Spring Security的权限控制

配置Spring Security的控制信息就是配置哪些页面需要登录的用户才能访问,登录的页面是那一个,登陆成功跳转到哪里等。以如下配置为例:所有的js等在resources文件夹下的内容都不需要经过过滤器,因为这些都是静态资源。而首页(/),登录页(/signin)、注册页(/register)等不需要用户登录,但是需要经过过滤器(因为我们可能需要获取未登录用户的一些信息)。两种配置方式如下所示。最后我们使用<form-login login-page="/signin" authentication-failure-url="/signin?login_error" default-target-url="/query"/>这个配置来说明登录页面是”/signin”,即所有需要用户登录的页面,在用户未登录情况下需要跳转到这个页面,让用户登录。authentication-failure-url配置的是用户登录失败的页面,而default-target-url是配置用户登录成功后跳转的页面。

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:beans="http://www.springframework.org/schema/beans"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-4.0.xsd">

  <!-- 配置为none的不经过任何spring的过滤器 -->
  <http pattern="/resources/**" security="none" />
  <http pattern="/sitemap.xml" security="none" />
  <http pattern="/favicon.ico" security="none" />

  <!-- 配置为permitAll允许用户访问,但依然经过过滤器处理 -->
  <http auto-config="true" use-expressions="true">

    <intercept-url pattern="/" access="permitAll" />
    <intercept-url pattern="/index*" access="permitAll" />
    <intercept-url pattern="/signin*" access="permitAll" />
    <intercept-url pattern="/login*" access="permitAll" />
    <intercept-url pattern="/register*" access="permitAll" />
    <intercept-url pattern="/invalidsession*" access="permitAll" />
    <intercept-url pattern="/404*" access="none" />

    <form-login login-page="/signin" authentication-failure-url="/signin?login_error" default-target-url="/query"/>
    <logout logout-success-url="/query" delete-cookies="JSESSIONID" />

    <intercept-url pattern="/admin" access="hasRole('ROLE_ADMIN')" />
    <intercept-url pattern="/**" access="hasAnyRole('ROLE_ADMIN','ROLE_USER')" />

    <csrf disabled="true" />
    <access-denied-handler error-page="/403" />

    <remember-me data-source-ref="dataSource" token-validity-seconds="1209600" remember-me-parameter="remember-me" />

    <session-management invalid-session-url="/">
      <concurrency-control max-sessions="1"/>
    </session-management>

  </http>

  <authentication-manager erase-credentials="false">
    <authentication-provider>
      <password-encoder ref="bcryptEncoder" />
      <jdbc-user-service data-source-ref="dataSource" />
    </authentication-provider>
  </authentication-manager>

  <beans:bean id="messageSource"
    class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <beans:property name="basenames">
      <beans:list>
        <beans:value>classpath:myMessages</beans:value>
      </beans:list>
    </beans:property>
  </beans:bean>

  <beans:bean name="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />

</beans:beans>

注意,这里定义了<beans:bean name="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />,表明登录的时候会对密码进行加密,那么后面我们写注册页面的时候必须要对密码加密之后才能存入数据库。

三、创建登录/注册的页面

这里属于前台的范畴,如果我们要使用Spring Security自带的验证方法,需要在前台也配置一样的信息来获取验证需要的字段,如用户名和密码。所以这里也是需要注意的地方。具体的页面核心代码如下(我们的页面使用了Bootstrap的前端工具,所以要引入bootrap和jquery等外部样式和脚本语言才会正常显示,但是这些显示不会影响功能,核心的字段不变即可):

<div class="container">

  <!-- 页面切换代码 -->
  <ul class="nav nav-tabs" id="loginTab" role="tablist">
    <li class="nav-item">
      <a class="nav-link active" id="home-tab" data-toggle="tab" href="#login" rel="external nofollow"
        role="tab" aria-controls="home" aria-expanded="true">登录</a>
    </li>
    <li class="nav-item">
      <a class="nav-link" id="home-tab" data-toggle="tab" href="#register" rel="external nofollow"
        role="tab" aria-controls="home" aria-expanded="true">注册</a>
    </li>
  </ul>

  <div class="tab-content" id="myTabContent">
    <!-- 登录页面 -->
    <div id="login" class="tab-pane fade show active" role="tabpanel" aria-labelledby="login-tab">
      <form class="form-signin" action="login" method="post">
        <label for="username" class="sr-only">Email address</label>
        <input type="email" name="username" id="username" class="form-control" placeholder="邮件地址">
        <label for="password" class="sr-only">Password</label>
        <input type="password" name="password" id="password" class="form-control" placeholder="密码">
        <button class="btn btn-lg btn-primary btn-block" type="submit">点击登录</button>
      </form>

    </div>

    <!-- 注册页面 -->
    <div id="register" class="tab-pane fade" role="tabpanel" aria-labelledby="register-tab">
      <div id="register_attention_alert_reg"></div>
      <form class="form-signin" onsubmit="return register()" method="post">
        <label for="registerEmail" class="sr-only">Email address</label>
        <input type="email" id="registerEmail" name="registerEmail" class="form-control" placeholder="邮件地址">
        <label for="registerPassword" class="sr-only">Password</label>
        <input type="password" name="password" id="registerPassword" class="form-control" placeholder="密码">
        <label for="inputPassword2" class="sr-only">Password</label>
        <input type="password" id="inputPasswordForRegister2" class="form-control" placeholder="请再次输入密码">
        <button class="btn btn-lg btn-primary btn-block" onclick="submit">点击注册</button>
      </form>
    </div>
  </div>

</div>

这里有两个Tab页代码,一个是登录Tab一个是注册Tab。主要是登录的Tab要和Spring Security一致,即登录的处理应当是login,即action="login",用户名的ID和name应该是username,而密码的应该是password,即提交给登录验证的两个参数应当是username和password,处理的请求页是login。

四、创建注册后台,定义登录处理

当登录注册页面做好之后,需要定义一下处理请求,即跳转的定义。然后只要写注册的后台就行了。注意一点,Spring Security的注册处理需要自己写个后台。用户提交注册后,我们需要把用户名和密码插入到数据库中,又一点注意了,由于我们之前配置了密码的加密,所以用户注册在插入数据库之前需要加密,否则后面无法验证通过。在注册用户的时候,我们需要更新users表的信息和authorities表信息,前者插入用户名和密码,并使得enabled=1(这个字段表示用户是否正常,=0的话,状态就是锁定的)。在authorities中要写入用户对应的角色(权限)。用户注册的时候密码加密的关键代码如下:

//插入users表的语句
String addUser = "insert into users(username,password) values(?,?)";

//对密码参数进行加密
String pwd = SpringSecurityUtil.encode(password);
Object[] param = {email, pwd};

//插入authorities表的语句
String addAuthority = "insert into authorities(username,authority) values(?,'ROLE_USER')";
Object[] authorityParam = {email};

int rows = 0;
try {
  rows = MyQueryRunnerUtil.getQueryRunner().update(addUser, param);
  rows += MyQueryRunnerUtil.getQueryRunner().update(addAuthority, authorityParam);
} catch (SQLException e) {
e.printStackTrace();
}

加密的代码如下:

/**
  * BCrypt加密(适用于注册时密码加密)
  *
  * @param rawPassword 明文密码
  * @return encoderPassword 密文密码,长度为60
  */
public static String encode(String rawPassword) {

  // 调用spring security的BCrypt加密
  BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
  String encoderPassword = encoder.encode(rawPassword);
  return encoderPassword;
}

这样,用户就可以注册了。注册好了就可以使用登录功能了。

总结一下Spring Security的登录验证关键步骤:

1、在数据库中建好三张表,即users、authorities和persistent_logins三个。注意字段的定义,不能少,可以多,名字必须按规定来。
2、在Spring Security的配置文件中,配置好登录跳转的页面,登录处理的页面和加密情况。
3、在前台的jsp页面中,登录的字段必须和后台users表中的一致,一般都是username和password。
4、注册页面必须自己写,注册的处理也要自己写。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • spring security自定义登录页面

    在项目中我们肯定不能使用Spring自己生成的登录页面,而要用我们自己的登录页面,下面讲一下如何自定义登录页面,先看下配置 <sec:http auto-config="true"> <sec:intercept-url pattern="/app.jsp" access="ROLE_SERVICE"/> <sec:intercept-url pattern="/**" access="

  • 详解Spring Security如何配置JSON登录

    spring security用了也有一段时间了,弄过异步和多数据源登录,也看过一点源码,最近弄rest,然后顺便搭oauth2,前端用json来登录,没想到spring security默认居然不能获取request中的json数据,谷歌一波后只在stackoverflow找到一个回答比较靠谱,还是得要重写filter,于是在这里填一波坑. 准备工作 基本的spring security配置就不说了,网上一堆例子,只要弄到普通的表单登录和自定义UserDetailsService就可以.因为需

  • 详解使用Spring Security进行自动登录验证

    在之前的博客使用SpringMVC创建Web工程并使用SpringSecurity进行权限控制的详细配置方法 中,我们描述了如何配置一个基于SpringMVC.SpringSecurity框架的网站系统.在这篇博客中,我们将继续描述如何使用Spring Security进行登录验证. 总结一下Spring Security的登录验证关键步骤: 1.在数据库中建好三张表,即users.authorities和persistent_logins三个.注意字段的定义,不能少,可以多,名字必须按规定来.

  • 详解使用Spring Security OAuth 实现OAuth 2.0 授权

    OAuth 2.0 是一种工业级的授权协议.OAuth 2.0是从创建于2006年的OAuth 1.0继承而来的.OAuth 2.0致力于帮助开发者简化授权并为web应用.桌面应用.移动应用.嵌入式应用提供具体的授权流程. OAuth 2.0 is the industry-standard protocol for authorization. OAuth 2.0 supersedes the work done on the original OAuth protocol created i

  • 详解在Spring中如何自动创建代理

    Spring 提供了自动代理机制,可以让容器自动生成代理,从而把开发人员从繁琐的配置中解脱出来 . 具体是使用 BeanPostProcessor 来实现这项功能. 1 BeanPostProcessor BeanPostProcessor 代理创建器的实现类可以分为 3 类: 类型 实现类 基于 Bean 配置名规则 BeanNameAutoProxyCreator 基于 Advisor 匹配规则 DefaultAdvisorAutoProxyCreator 基于 Bean 中的 Aspect

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

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

  • 详解用Spring Boot Admin来监控我们的微服务

    1.概述 Spring Boot Admin是一个Web应用程序,用于管理和监视Spring Boot应用程序.每个应用程序都被视为客户端,并注册到管理服务器.底层能力是由Spring Boot Actuator端点提供的. 在本文中,我们将介绍配置Spring Boot Admin服务器的步骤以及应用程序如何集成客户端. 2.管理服务器配置 由于Spring Boot Admin Server可以作为servlet或webflux应用程序运行,根据需要,选择一种并添加相应的Spring Boo

  • 详解JAVA Spring 中的事件机制

    说到事件机制,可能脑海中最先浮现的就是日常使用的各种 listener,listener去监听事件源,如果被监听的事件有变化就会通知listener,从而针对变化做相应的动作.这些listener是怎么实现的呢?说listener之前,我们先从设计模式开始讲起. 观察者模式 观察者模式一般包含以下几个对象: Subject:被观察的对象.它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法notify().目标类可以是接口,也可以是抽象类或具体类. ConcreteSubject:具体的

  • Spring Security 表单登录功能的实现方法

    1.简介 本文将重点介绍使用 Spring Security 登录. 本文将构建在之前简单的 Spring MVC示例 之上,因为这是设置Web应用程序和登录机制的必不可少的. 2. Maven 依赖 要将Maven依赖项添加到项目中,请参阅Spring Security with Maven 一文. 标准的 spring-security-web 和 spring-security-config 都是必需的. 3. Spring Security Java配置 我们首先创建一个扩展 WebSe

  • 详解基于Spring Data的领域事件发布

    领域事件发布是一个领域对象为了让其它对象知道自己已经处理完成某个操作时发出的一个通知,事件发布力求从代码层面让自身对象与外部对象解耦,并减少技术代码入侵. 一. 手动发布事件 // 实体定义 @Entity public class Department implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer departmentId; @Enumerate

  • Spring Security实现自动登陆功能示例

    当我们在登录像QQ邮箱这种大多数的网站,往往在登录按键上会有下次自动登录这个选项,勾选后登录成功,在一段时间内,即便退出浏览器或者服务器重启,再次访问不需要用户输入账号密码进行登录,这也解决了用户每次输入账号密码的麻烦. 接下来实现自动登陆. applicatio.properties配置用户名密码 spring.security.user.name=java spring.security.user.password=java controller层实现 @RestController pub

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

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

随机推荐