【详解】核心组件之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框 ...
随机推荐
- sublime text配置node.js调试
1. 首先到 nodejs.org 下载 Node.js 安装包并安装.2. 打开 Sublime Text 2 编辑器.选择菜单 Tools --> Build System --> n ...
- hadoop和spark相关参数的配置
背景 MapReduce和Spark对外提供了上百个配置参数,用户可以为作业定制这些参数以更快,更稳定的运行应用程序.本文梳理了最常用的一些MapReduce和Spark配置参数. MapReduce ...
- Bloom Filter 算法简介 (增加 Counting Bloom Filter 内容)
Bloom Filter的中文翻译叫做布隆过滤器,是1970年由布隆提出的.它实际上是一个很长的二进制向量和一系列随机映射函数.布隆过滤器可以用于检索一个元素是否在一个集合中.它的优点是空间效率和查询 ...
- Scala_对象
对象 单例对象 Scala并没有提供Java那样的静态方法或静态字段,但是,可以采用 object关键字实现单例对象,具备和Java静态方法同样的功能. 可以看出,单例对象的定义和类的定义很相似,明显 ...
- node-lessons
教程:https://github.com/alsotang/node-lessons 0 nvm 的全称是 Node Version Manager,之所以需要这个工具,是因为 Node.js 的各 ...
- 验证手机格式的js代码
function isMobil(s) { var patrn = /(^0{0,1}1[3|4|5|6|7|8|9][0-9]{9}$)/; ...
- Oracle EBS登陆后,直接打开某个特定Form/Page
http://blog.csdn.net/pan_tian/article/details/8169339 有一个小技巧,Oracle EBS登陆后可以绕过职责和功能的选择过程,就可以直接打开某个特定 ...
- cxGrid之checkbox小结
http://www.cnblogs.com/Kim53622744/p/4428997.html 在cxgrid中增加选择列 1.在dataset(query/table/clientdataset ...
- unity 人工智能AI,装备解锁临时笔记
A*算法的一种改进设想:1.如何让角色到达目标点的过程中更加平滑:获取一串到达目标点的网格串之后,就实时用带形状的物理射线检测能否直接到达下一个目标点的再下一个目标点,如果能到达,那么直接朝该方向运动 ...
- 【转】selenium webdriver三种等待方法
原文:https://www.cnblogs.com/lgh344902118/p/6015593.html webdriver三种等待方法 1.使用WebDriverWait from seleni ...