【详解】核心组件之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框 ...
随机推荐
- java类与继承(转载)
关于java的类与继承面链接是一个网友总结的,还有列子我个人觉得很详细 固拿来收藏,需要的朋友可从这里访问: http://www.cnblogs.com/dolphin0520/p/3803432. ...
- java 判断手机号码和邮箱的正则表达式
很多场合会用到判断输入框输入的是否为手机或者邮箱,下面是这个正则表达式: Pattern patternMailBox = Pattern .compile( "^([a-zA-Z0-9 ...
- EBS 定义显示总帐快码设置
自定义一个功能如下,挂到菜单上就可以了功能 用户功能名 表单 参数GL_GLXDQMLK(自定义) 总帐代码列表 定义代码 VIEW_APPLICATION="SQLGL" HEL ...
- Android-Could not find method implementation() for arguments
当AndroidStudio加载工程的时候:报以下错误: 详细错误: Could not find method implementation() for arguments [file collec ...
- Android-Kotlin-印章类
上一篇博客介绍了,Android-Kotlin-枚举enum: 由于枚举 和 印章类 有相似之处,所以两者对比一下: Kotlin的枚举,重点区分的数据本身 Kotlin的印章类,重点区分的是数据类型 ...
- Convolution Neural Network (CNN) 原理与实现
本文结合Deep learning的一个应用,Convolution Neural Network 进行一些基本应用,参考Lecun的Document 0.1进行部分拓展,与结果展示(in pytho ...
- cnn的说明
概述 前面的练习中,解决了一些有关低分辨率图像的问题,比如:小块图像,手写数字小幅图像等.在这部分中,我们将把已知的方法扩展到实际应用中更加常见的大图像数据集. 全联通网络 在稀疏自编码章节中,我们介 ...
- jacoco初探
# 背景 集团的代码覆盖率平台因为网络问题无法使用,只能自己研究下. 覆盖率是衡量自动化用例效果产品的一个指标,但只是一个辅助指标,覆盖率高并不意味着质量好,但覆盖率低却能说明一些问题, # 对比 覆 ...
- 【系统架构】亿级Web系统搭建(1):Web负载均衡
当一个Web系统从日访问量10万逐步增长到1000万,甚至超过1亿的过程中,Web系统承受的压力会越来越大,在这个过程中,我们会遇到很多的问题.为了解决这些性能压力带来问题,我们需要通过搭建不同的服务 ...
- ASP.NET MVC 项目设置,移除多余的响应头,woff,woff2 字体文件请求处理
移除 X-AspNetMvc-Version 在 Global.asax 的 Application_Start添加代码 MvcHandler.DisableMvcResponseHeader = t ...