【详解】核心组件之UserDetailService
简介
- UserDetails => Spring Security基础接口,包含某个用户的账号,密码,权限,状态(是否锁定)等信息。只有getter方法。
- Authentication => 认证对象,认证开始时创建,认证成功后存储于SecurityContext
- principal => 用户信息对象,是一个Object,通常可转为UserDetails
UserDetails接口
用于表示一个principal,但是一般情况下是作为(你所使用的用户数据库)和(Spring Security 的安全上下文需要保留的信息)之间的适配器。
实际上就是相当于定义一个规范,Security这个框架不管你的应用时怎么存储用户和权限信息的。只要你取出来的时候把它包装成一个UserDetails对象给我用就可以了。
package org.springframework.security.core.userdetails; import java.io.Serializable;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority; public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities(); String getPassword(); String getUsername(); boolean isAccountNonExpired(); boolean isAccountNonLocked(); boolean isCredentialsNonExpired(); boolean isEnabled();
}
UserDetails用来做什么?为什么还要带上权限集合?
如果我们不用认证框架,我们是怎么手动实现登录认证的?
基本上就是根据前端提交上来的用户名从数据库中查找这个账号的信息,然后比对密码。再进一步,可能还会添加一个字段来判断,当前用户是否已被锁定。这个接口就是这么用的。即把这些信息取出来,然后包装成一个对象交由框架去认证。
为什么还要带上权限?
因为登录成功后也不是什么都能访问的,还要根据你所拥有的权限进行判断。有权限你才能访问特定的对象。Security框架是这样设计的,即认证成功后,就把用户信息和拥有的权限都存储在SecurityContext中,当访问受保护资源(某个对象/方法)的时候,就把权限拿出来比对,看看是否满足。
框架提供的UserDetails默认实现
public class User implements UserDetails, CredentialsContainer {
private static final long serialVersionUID = 500L;
private static final Log logger = LogFactory.getLog(User.class);
private String password;
private final String username;
private final Set<GrantedAuthority> authorities;
private final boolean accountNonExpired;
private final boolean accountNonLocked;
private final boolean credentialsNonExpired;
private final boolean enabled;
public User(String username, String password, Collection<? extends GrantedAuthority> authorities) {
this(username, password, true, true, true, true, authorities);
}
public User(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
if (username != null && !"".equals(username) && password != null) {
this.username = username;
this.password = password;
this.enabled = enabled;
this.accountNonExpired = accountNonExpired;
this.credentialsNonExpired = credentialsNonExpired;
this.accountNonLocked = accountNonLocked;
this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
} else {
throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
}
}
//省略部分代码
}
什么时候提供UserDetails信息,怎么提供?
UserDetailsService接口
那肯定是认证的时候。其实认证的操作,框架都已经帮你实现了,它所需要的只是,你给我提供获取信息的方式。所以它就定义一个接口,然后让你去实现,实现好了之后再注入给它。
框架提供一个UserDetailsService接口用来加载用户信息。如果要自定义实现的话,用户可以实现一个CustomUserDetailsService的类,然后把你的应用中的UserService和AuthorityService注入到这个类中,用户获取用户信息和权限信息,然后在loadUserByUsername方法中,构造一个User对象(框架的类)返回即可。
package org.springframework.security.core.userdetails;
public interface UserDetailsService {
UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}
框架提供的UserDetailsService接口默认实现
- InMemoryDaoImpl => 存储于内存
- JdbcDaoImpl => 存储于数据库(磁盘)
其中,如果你的数据库设计符合JdbcDaoImpl中的规范,你也就不用自己去实现UserDetailsService了。但是大多数情况是不符合的,因为你用户表不一定就叫users,可能还有其他前缀什么的,比如叫tb_users。或者字段名也跟它不一样。如果你一定要使用这个JdbcDaoImpl,你可以通过它的setter方法修改它的数据库查询语句。
注:它是利用Spring框架的JdbcTemplate来查询数据库的
public class JdbcDaoImpl extends JdbcDaoSupport implements UserDetailsService, MessageSourceAware {
public static final String DEF_USERS_BY_USERNAME_QUERY = "select username,password,enabled from users where username = ?";
public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY = "select username,authority from authorities where username = ?";
public static final String DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY = "select g.id, g.group_name, ga.authority from groups g, group_members gm, group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id";
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
private String authoritiesByUsernameQuery = "select username,authority from authorities where username = ?";
private String groupAuthoritiesByUsernameQuery = "select g.id, g.group_name, ga.authority from groups g, group_members gm, group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id";
private String usersByUsernameQuery = "select username,password,enabled from users where username = ?";
private String rolePrefix = "";
private boolean usernameBasedPrimaryKey = true;
private boolean enableAuthorities = true;
private boolean enableGroups;
//省略方法
}
注入到哪里去呢?
那肯定是注入到认证处理类中的,框架利用AuthenticationManager(接口)来进行认证。而Security为了支持多种方式认证,它提供ProviderManager类,这个实现了AuthenticationManager接口。它拥有多种认证方式,可以根据认证的类型委托给对应的认证处理类进行处理,这个处理类实现了AuthenticationProvider接口。
误解
【详解】核心组件之UserDetailService的更多相关文章
- ansible安装与核心组件详解
第1章 安装anisble 1.1 安装epel源 rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarc ...
- Log4Net使用详解
1.Log4Net环境的搭建与基本配置 (1)Log4Net框架介绍 Log4net 是 Apache 下一个开放源码的项目,它是Log4j 的一个克隆版.我们可以控制日志信息的输出目的地.L ...
- [转]AndroidManifest.xml文件详解
转自:http://www.cnblogs.com/greatverve/archive/2012/05/08/AndroidManifest-xml.html AndroidManifest.xml ...
- 20160206.CCPP体系详解(0016天)
代码片段(01):.指针.c+02.间接赋值.c 内容概要:内存 ///01.指针 #include <stdio.h> #include <stdlib.h> //01.取地 ...
- Solr部署详解
Solr部署详解 时间:2013-11-24 方式:转载 目录 1 solr概述 1.1 solr的简介 1.2 solr的特点 2 Solr安装 2.1 安装JDK 2.2 安装Tomcat 2.3 ...
- Springboot启动源码详解
我们开发任何一个Spring Boot项目,都会用到如下的启动类 @SpringBootApplication public class Application { public static voi ...
- 史上最易懂——ReactNative分组列表SectionList使用详情及示例详解
React Native系列 <逻辑性最强的React Native环境搭建与调试> <ReactNative开发工具有这一篇足矣> <解决React Native un ...
- 详解Tomcat 配置文件server.xml
前言 Tomcat隶属于Apache基金会,是开源的轻量级Web应用服务器,使用非常广泛.server.xml是Tomcat中最重要的配置文件,server.xml的每一个元素都对应了Tomcat中的 ...
- Java web 入门知识 及HTTP协议详解
Java web 入门知识 及HTTP协议详解 WEB入门 WEB,在英语中web即表示网页的意思,它用于表示Internet主机上供外界访问的资源. Internet上供外界访问的Web资 ...
- [转载] 多图详解Spring框架的设计理念与设计模式
转载自http://developer.51cto.com/art/201006/205212_all.htm Spring作为现在最优秀的框架之一,已被广泛的使用,51CTO也曾经针对Spring框 ...
随机推荐
- 04:第一个OC类
1.类与对象的关系 面向对象的核心就是对象,那怎么创建对象? OC中创建对象比较复杂, 首先要理解一个概念叫做类. 现实生活中是根据一份描述,一份模板创建对象,编程语言也一样,也必须先有一份描述,在这 ...
- QT中的线程与事件循环理解(2)
1. Qt多线程与Qobject的关系 每一个 Qt 应用程序至少有一个事件循环,就是调用了QCoreApplication::exec()的那个事件循环.不过,QThread也可以开启事件循环.只不 ...
- jvm虚拟机--堆内存
reserved 保留区域 堆 所有对象实例都在这里分配内存. 是垃圾收集的主要区域("GC 堆").现代的垃圾收集器基本都是采用分代收集算法,主要思想是针对不同的对象采取不同的垃 ...
- XE7 & FMX 那些年我们一起上过的控件:ListView 之 (3) 加载数据时如何显示自定义样式
本文介绍一下ListView下如何加载数据.及使用进度条反馈当前进度给用户. 注意: 原创作品,请尊重作者劳动成果,转载请注明出处!!!原文永久固定地址:http://www.cnblogs.com/ ...
- linux中yum命令的解析
yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及SUSE中的Shell前端软件包管理器.基於RPM包管理,能够从指定的服务器自动下载RP ...
- Git清空历史,清空历史删除的文件,降低.git 文件大小
执行以下步骤之前 请做好源码备份 本操作用来清理github上面的历史删除文件,减少库的体积. 第一步骤 下载JDK环境和JAR包 https://rtyley.github.io/bfg-repo- ...
- web端权限维持【好文】
前言 关于权限维持,我之前写过一篇基于系统端的后门技术文章,如映像劫持啊,lpk之类. 内容目录: - 构造文件包含漏洞- 隐蔽性脚本木马- 构造sql注入点 正文 0x01 构造文件包含漏洞 > ...
- @JsonInclude、@JsonFormat、@DateTimeFormat注解的使用
@JsonInclude(value=Include.NON_NULL) :用在实体类的方法类的头上 作用是实体类的参数查询到的为null的不显示 @DateTimeFormat:用于接收 前端传的 ...
- Java内存溢出问题总结
使用Java那么久,在此总结一下Java中常见的内存溢出问题以及对应的解决思路 堆溢出 报错信息 java.lang.OutOfMemoryError: Java heap space 报错原因 堆中 ...
- C#6.0语言规范(九) 命名空间
C#程序使用命名空间进行组织.命名空间既可以用作程序的“内部”组织系统,也可以用作“外部”组织系统 - 一种呈现暴露给其他程序的程序元素的方式. 提供了使用指令(使用指令)以便于使用命名空间. 编译单 ...