第一章我们基于内存中的用户信息实现了一个基本的登入功能,不过实际的项目中用户信息一般都是存在数据库中的。本章我们来实现一个比较接近真实项目的登入登出,同时引入UserDetailsService的概念。

UserDetailsService和UserDetail

思考一下,如果不用框架,我们自己要实现一个用户登录认证会怎么做?

其实也不难,思路就是根据提交上来的用户名和密码,从数据库中查找这个账号的信息进行对比。再进一步,可能还包含一些额外的信息,比如用户是否被锁定等。这些基础的功能框架大部分都已经帮我们做好了,我们只要实现一些细节(实现UserDetailsService接口)就可以了。

图片来自网络

官方是这么说的:

The AuthenticationManager is just an interface, so the implementation can be anything we choose, but how does it work in practice? What if we need to check multiple authentication databases or a combination of different authentication services such as a database and an LDAP server?

The default implementation in Spring Security is called ProviderManager and rather than handling the authentication request itself, it delegates to a list of configured AuthenticationProvider s, each of which is queried in turn to see if it can perform the authentication. Each provider will either throw an exception or return a fully populated Authentication object. Remember our good friends, UserDetails and UserDetailsService? If not, head back to the previous chapter and refresh your memory. The most common approach to verifying an authentication request is to load the corresponding UserDetails and check the loaded password against the one that has been entered by the user. This is the approach used by the DaoAuthenticationProvider (see below). The loaded UserDetails object - and particularly the GrantedAuthority s it contains - will be used when building the fully populated Authentication object which is returned from a successful authentication and stored in the SecurityContext.

它的大概意思是,

Spring Security中进行身份验证的是AuthenticationManager接口,ProviderManager是它的一个默认实现,但它并不用来处理身份认证,而是委托给AuthenticationProvider,每个AuthenticationProvider会轮流检查身份认证。检查后或者返回Authentication对象或者抛出异常。

最常用的验证身份的方法就是加载UserDetails,看看是否和用户输入的账号、密码、权限等信息匹配。此步骤由DaoAuthenticationProvider(它利用UserDetailsService验证用户名、密码和授权)处理。包含 GrantedAuthority 的 UserDetails对象在构建 Authentication对象时填入数据。

所以实现UserDetailsService接口是我们一个核心的工作。

准备数据库

数据库里我们准备了一张用户信息表,存放用户的账户信息(用户名,密码等)。准备了两条测试数据

zhangsan/12345678lisi/11111111

数据库操作使用的是spring data JPA ORM框架,这个知识点不在本章的讲述范围内,请自行查阅。

实现UserDetailsService

public class MyUserDetailsService implements UserDetailsService {    @Autowired    private UserRepository userRepository;    @Override    public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {        MyUser user = userRepository.findByUsername(name);        if(user == null){            throw new UsernameNotFoundException(name);        }        String password = user.getPassword();        String encode = new BCryptPasswordEncoder().encode(password);        Collection authList = getAuthorities();        return new User(name, encode, true, true, true, true,authList);    }    private Collection getAuthorities(){        List authList = new ArrayList();        //这里添加的角色,实际项目中应该根据用户信息从数据库中获取,这里为了简单起见直接赋值。        authList.add(new SimpleGrantedAuthority("ROLE_ADMIN"));        //也可以继续添加其它角色        return authList;    }}

代码很简单,UserDetailsService的loadUserByUsername方法,通过username来获取user信息,这个信息被封装在 UserDetails对象,然后spring security用这个对象进行身份验证。

User是系统自带的UserDetails实现类,我们也可以自己定义一个UserDetails实现类。UserDetails包含用户名,密码,权限还有四个状态,其中任何一个为false都会报异常。因为我们的数据库里的用户信息没有状态字段,这里就用true填充即可。

注意密码我们是传入的加密后的结果

添加注销的操作

spring security在实现注销功能的大概流程是:

  1. 使得HTTP session失效(如果invalidate-session属性被设置为true)
  2. 清空remember me
  3. 清除SecurityContex
  4. 将页面重定向至logout-success-url指明的URL。

首先是要在配置退出的逻辑,

   protected void configure(HttpSecurity http) throws Exception {              http.authorizeRequests()                   .anyRequest()                   .authenticated()                   .and()                   .formLogin().loginPage("/login").defaultSuccessUrl("/user").permitAll()                   .and().logout().permitAll()                   .logoutSuccessHandler(logoutSuccessHandler())   //                .logoutSuccessUrl("/login")                   .and()                   .csrf().disable();          }

logoutSuccessHandler接口定义了注销之后的操作方法,这个接口不一定要实现,我这里的实现只是简单打印日志,并且重定向到login登录页。

    @Bean        LogoutSuccessHandler logoutSuccessHandler(){            return  new LogoutSuccessHandler() {                @Override                public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {                    System.out.println("你退出了登录");                    httpServletResponse.sendRedirect("/login");                }            };        }

简单的场景下,logoutSuccessHandler一般不需要写,spring security支持通过logoutSuccessUrl快捷的指明注销后跳转的页面(需要注意的是对应的URL应当是不需要登录就可以访问的),如果指定了LogoutSuccessHandler,logoutSuccessUrl() 会被忽略。

在REST API的场景下,一般我们都是需要定义logoutSuccessHandler的。这种场景下当注销成功后,不是重定向到一个URL,而是需要提供一个JSON格式的纯文本 HTTP 状态码返回。

接着我们再首页和用户页的html文件中加入注销的操作,

        
这是首页

注销

这里可能会有疑问,controller并没有定义logout处理入口,会不会报错呢? 其实spring security已经帮我们默认处理了名为logout的退出操作。 当然我们也可以通过logoutUrl配置自定义注销的处理入口。

另外需要注意的是,因为前面登录页是用的自定义页面,注销的处理需要指明使用POST,否则会报错。

测试

启动工程,进行如下测试:

  1. 访问首页,http://localhost:9090,需要授权,会自动跳入登录页:http://localhost:9090/login
  2. 从登录页输入用户名和密码(看数据库里的信息),进入用户主页
  3. 点击注销按钮,进入login页面

实现账号在一端登入_跟我学spring security 基于数据库实现一个基本的登入登出...相关推荐

  1. 跟我学spring security系列文章第一章 实现一个基本的登入

    文章目录 指定依赖 安全配置 添加controller测试代码 测试 源码地址: https://github.com/pony-maggie/spring-security-learn 指定依赖 s ...

  2. 004-云E办_学习Oathu2和Spring Security Oauth2

    这里写目录标题 一.Oauth2简介 1.简介 2.分析Oauth2认证的例子,网站使用微信认证的过程: 3.Oauth2.0认证流程如下: 1.角色: 2.常用术语: 3.令牌类型 4.特点 二.授 ...

  3. webmvcconfigurer配置跨域_为什么加了 Spring Security 会导致 Spring Boot 跨域失效呢?...

    点击上方 IT牧场 ,选择 置顶或者星标 技术干货每日送达 作者:欧阳我去 链接:https://segmentfault.com/a/1190000019485883 作为一个后端开发,我们经常遇到 ...

  4. hystrix 全局熔断_跟我学Spring Cloud(Finchley版)14Feign使用Hystrix

    Feign默认已经整合了Hystrix,本节详细探讨Feign使用Hystrix的具体细节. 服务降级 1 加配置,默认Feign是不启用Hystrix的,需要添加如下配置启用Hystrix,这样所有 ...

  5. hibernate 读取mysql表结构_为什么要用hibernate 与基于数据库表结构的项目开发

    最近开始学习hibernate,其实并不知道要学习什么,有什么用.后来问了一下同事,他就说快捷方便简单,很多事情不用自己做他会帮你做好,但是我觉得不应该是这样的, 于是我就去搜了一下,就搜到了一篇帖子 ...

  6. mysql 手工配置_小姜学网络(MySQL数据库的手工安装与配置)附代码

    完成小姜学网络(先电IaaS云平台基本环境配置二)附带完整代码中所有内容,即先电IaaS云平台基本环境配置,或者从小姜学网络(先电IaaS云平台基本环境配置一)附带完整代码的镜像开始 涉及节点: co ...

  7. java 账本 创建数据库_想用你所学的JAVA与数据库写一个属于自己的账本吗?一起来看看呗!看如何用java项目操作数据库...

    *利用简单的JAVA与数据库写一个属于你自己的账本* 效果图 * 目标实现 把用户输入的信息录入到数据库中,并且从数据库中取出值来,是不是很简单? 所需工具 相信大家都有的,eclipse.myecl ...

  8. win10 SystemParametersInfo 设置屏保 不好使_黑科技学:抖音最近很火的时间罗盘屏保出电脑版了,实在太帅了...

    自古深情留不住,唯有套路存人心,大家好我是你们的黑科技老师木子李.今天小编想和大家分享一下最近很火的时间罗盘屏保,最近很多教程都是手机版,所以今天小编这出的是电脑版!动画效果那是相当的优秀.有什么需要 ...

  9. 从零开始java安全权限框架篇(一):spring security配置登录登出的配置

    目录 一:安全权限框架的选取 二:功能 三:登录登出 四:代码注释 1.将登陆交由Spring security完成 2.前台明文密码加密,与数据库比对 3.关键配置 4.自定义用户异常 5.ajax ...

最新文章

  1. 用 GStreamer 简化 Linux 多媒体开发
  2. 数据研发岗位需要技能
  3. 【实战分享】安卓app测试的一些记录
  4. 疯抢当当图书 618 优惠码,花 120 买 300
  5. spring security实现登录验证以及根据用户身份跳转不同页面
  6. 5g消息服务器,《5G消息白皮书》内容解读:5G消息是什么服务?
  7. 搜狗语音输入提示服务器繁忙,讯飞语音输入如何提高识别率 提高方法
  8. 松下年净利润预计降20% 或启动新一轮裁员
  9. 如何给小朋友解释单摆运动_模仿小天才钟美美:小朋友都是天生的演员?
  10. UVA 644 - Immediate Decodability
  11. openfire无法启动
  12. 对象释放函数kmem_cache_free核心函数slab_free的实现详解
  13. U深度-重装电脑系统
  14. 为什么Java小伙对JavaScript和Node.js如此兴奋?
  15. 宇枫资本投资理财投资入门与技巧
  16. 做好加密手机 任重而道远
  17. OO第四单元作业小结
  18. vm文件,.vm后缀的文件
  19. 实现一个脚本引擎(燕良译)- -
  20. win10麦克风说话没声音_怎样选主播麦克风

热门文章

  1. 五、MySql索引基本介绍
  2. ajax datatype为html,Jquery ajax请求中datatype的含义
  3. python 打印异常内容_python打印异常信息的两种实现方式
  4. 合并报表编制采用的理论_合并报表操作的整体思路梳理
  5. php xml转化为html,php将xml文件转换为html Web程序 - 贪吃蛇学院-专业IT技术平台
  6. 冒泡排序出现的问题_停课不停学 | 有趣的算法——冒泡排序
  7. 两张照片重叠处半透明_美人计 | 林允儿的发型可真好看!拿着照片去找发型师吧...
  8. 滇西应用技术大学计算机专业录取分数线,滇西应用技术大学录取分数线2021是多少分(附历年录取分数线)...
  9. php yield 导出文件,PHP yield 读取大文件
  10. java volatile 多线程_Java多线程之volatile