(三)spring Security 从数据库中检索用户名和密码
文章目录
配置 Druid 数据源
配置 Druid 数据源,看下这篇博客,至于后面的添加监控那些就不用看了,仅仅看如何整合的 ;
数据库
需要创建 user、role、role_user 表。建表语句我已经写好了:
CREATE TABLE IF NOT EXISTS USER (
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
name VARCHAR(10),
password VARCHAR(50)
)
CHARSET utf8;
CREATE TABLE IF NOT EXISTS ROLE (
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
name VARCHAR(10)
)
CHARSET utf8;
CREATE TABLE IF NOT EXISTS ROLE_USER (
user_id INT,
role_id INT
)
CHARSET utf8;
# 防止项目启动,出现重复插入而报错
INSERT INTO `ROLE` (`id`, `name`) SELECT
'1',
'ROLE_ADMIN'
FROM dual
WHERE NOT exists(SELECT id
FROM `ROLE`
WHERE id = '1');
INSERT INTO `ROLE` (`id`, `name`) SELECT
'2',
'ROLE_USER'
FROM dual
WHERE NOT exists(SELECT id
FROM `ROLE`
WHERE id = '2');
INSERT INTO `USER` (`id`, `password`, `name`) SELECT
'1',
'root',
'root'
FROM dual
WHERE NOT exists(SELECT id
FROM `USER`
WHERE id = '1');
INSERT INTO `USER` (`id`, `password`, `name`) SELECT
'2',
'yiaz',
'yiaz'
FROM dual
WHERE NOT exists(SELECT id
FROM `USER`
WHERE id = '2');
INSERT INTO `ROLE_USER` (`user_id`, `role_id`) SELECT
'1',
'1'
FROM dual
WHERE NOT exists(SELECT user_id
FROM `ROLE_USER`
WHERE user_id = '1');
INSERT INTO `ROLE_USER` (`user_id`, `role_id`) SELECT
'2',
'2'
FROM dual
WHERE NOT exists(SELECT user_id
FROM `ROLE_USER`
WHERE user_id = '2');
执行下即可。或者自己写,也行;
Mapper 文件
public interface LoginMapper {
@Select("select * from user where name = #{name}")
MyUser loadUserByUsername(String name);
@Select("SELECT role.`name` FROM role WHERE role.id in (SELECT role_id FROM " +
" role_user as r_s JOIN `user` as u ON r_s.user_id = u.id and u.id = #{id})")
List<Role> findRoleByUserId(int id);
}
自定义 UserDetailsService
UserDetailsService 的主要作用是,获取数据库里面的信息,然后封装成对象,我们既然需要从数据库中读取用户,那么我们就需要实现自己的 UserDetailsService ,按照我们的逻辑完成从数据库中获取信息;
/**
* 主要是封装从数据库获取的用户信息
*
* @author yiaz
* @date 2019年3月19日10:50:58
*/
@Component
public class UserDetailServiceImpl implements UserDetailsService {
// demo 不想写 service层,直接 dao 层穿透到 controller 层
@Autowired
private LoginMapper loginMapper;
@Override
public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
// 根据用户名查询数据库,查到对应的用户
MyUser myUser = loginMapper.loadUserByUsername(name);
// ... 做一些异常处理,没有找到用户之类的
if(myUser == null){
throw new UsernameNotFoundException("用户不存在") ;
}
// 根据用户ID,查询用户的角色
List<Role> roles = loginMapper.findRoleByUserId(myUser.getId());
// 添加角色
List<GrantedAuthority> authorities = new ArrayList<>();
for (int i = 0; i < roles.size(); i++) {
authorities.add(new SimpleGrantedAuthority(roles.get(i).getName()));
}
// 构建 Security 的 User 对象
User user = new User(myUser.getName(), myUser.getPassword(), authorities);
return user;
}
}
自定义登陆校验器 AuthenticationProvider
我们既然不用 security 来帮我们检验,就要实现自己的校验逻辑,实现自己的 AuthenticationProvider 类,完成校验 ;
BCryptPasswordEncoder 是完成加盐MD5 的一个类,很棒,思路和笔者许久之前想到的差不多。不需要我们去管理盐值的问题,也不需要在数据库里面进行存储了;
/**
* 完成校验工作
*/
@Component
public class MyAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserDetailServiceImpl userDetailService;
/**
* 进行身份认证
*
* @param authentication
* @return
* @throws AuthenticationException
*/
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 获取用户输入的用户名和密码
String username = authentication.getName();
String password = authentication.getCredentials().toString();
// 获取封装用户信息的对象
UserDetails userDetails = userDetailService.loadUserByUsername(username);
// 进行密码的比对
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
boolean flag = bCryptPasswordEncoder.matches(password, userDetails.getPassword());
// 校验通过
if (flag){
// 将权限信息也封装进去
return new UsernamePasswordAuthenticationToken(userDetails,password,userDetails.getAuthorities());
}
// 验证失败返回 null
return null;
}
/**
* 这个方法 确保返回 true 即可,
*
* @param aClass
* @return
*/
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
配置 security
将之前的 WebSecurityConfig 类中的 WebSecurityConfigurerAdapter 做如下修改:
/**
* security 配置
* @param myAuthenticationProvider
* @return
*/
@Autowired
@Bean
public WebSecurityConfigurerAdapter webSecurityConfigurerAdapter(MyAuthenticationProvider myAuthenticationProvider) {
/**
* 配置对哪些路径进行拦截,如果方法里面什么都不写,则不拦截任何路径;
* <p>
* 如果,使用 super.configure(http),父类的方法:
* ((HttpSecurity)((HttpSecurity)((AuthorizedUrl)http.authorizeRequests().anyRequest()).authenticated().and()).formLogin().and()).httpBasic();
* <p>
* 我们自定义下拦截规则,表单等一系列规则;
*/
return new WebSecurityConfigurerAdapter() {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
// 放行登录
.antMatchers("/login/**").permitAll()
.anyRequest().authenticated()
.and()
// 开启表单认证
.formLogin()
// 地址写的是 映射的路径
.loginPage("/login.html")
// 必须添加
.loginProcessingUrl("/login")
.permitAll()
// 第二个参数,如果不写成true,则默认登录成功以后,访问之前被拦截的页面,而非去我们规定的页面
.defaultSuccessUrl("/index.html", true)
.and()
.logout()
.logoutUrl("/logout")
.and()
.csrf()
.disable()
.httpBasic();
}
/**
* 配置自定义校验规则,密码编码,使用我们自定义的校验器
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(myAuthenticationProvider);
}
};
}
其中 loginProcessingUrl("/login") 必须写上,否则会报 405 错误 ,其中后面的参数值,写成,你自定义表单的提交地址;
后记
这样就完成了,也不难,就是有点坑,浪费了我一天时间,之前没写上 loginProcessingUrl("/login") 大家也没提到这个问题,导致一直 405 ,如果你也遇到 405 ,兴许你花了2分钟看完,就搞定了!
其实即使我们自定义了检验规则,其实我们也没有完全接手 security ,只是在其运行期间,参与了一个环节,给它一个我们自定义的检验器,让它使用我们的检验器;
(三)spring Security 从数据库中检索用户名和密码的更多相关文章
- spring security进阶 使用数据库中的账户和密码认证
目录 spring security 使用数据库中的账户和密码认证 一.原理分析 二.代码实现 1.新建一个javaWeb工程 2.用户认证的实现 3.测试 三.总结 spring security ...
- Spring Security使用数据库数据完成认证--练气后期2
写在前面 没错,这篇文章还是练气后期!但作者我相信筑基指日可待! 在前一篇文章当中,我们简单地分析了一下Spring Security的认证流程,知道了如果想要实现对自己用户数据(账户.角色.权限)的 ...
- Spring Security 3.1 中功能强大的加密工具 PasswordEncoder
Spring Security 3.1 中功能强大的加密工具 PasswordEncoder 博客分类: security spring springsecurity 好吧,这种加密机制很复杂,还是 ...
- git 中添加用户名和密码
git 中添加用户名和密码:https://blog.csdn.net/qq_28602957/article/details/52154384 在使用git时,如果用的是HTTPS的方式,则每次提交 ...
- spring security结合数据库验证用户-XML配置方式
之前的用户信息我们都是使用的内存用户,测试例子可以,实际中使用肯定不行,需要结合数据库进行验证用户.这就是本节的重点: 项目目录如下: 在之前的项目中的依赖中添加两个依赖: <dependen ...
- spring security使用数据库资源
国内对权限系统的基本要求是将用户权限和被保护资源都放在数据库里进行管理,在这点上Spring Security并没有给出官方的解决方案,为此我们需要对Spring Security进行扩展.. 数据库 ...
- spring security使用数据库验证的逻辑处理
前面做了多个示例,包括使用jdbc和hibernate两种方式访问数据库获取用户信息和权限信息,其中一些关键步骤如下: 我们在SecurityConfig中配置覆盖configure方法时候,可以 ...
- spring boot系列--spring security (基于数据库)登录和权限控制
先说一下AuthConfig.java Spring Security的主要配置文件之一 AuthConfig 1 @Configuration 2 @EnableWebSecurity 3 publ ...
- Spring Security 使用数据库用户进行认证
本文参考或摘录自:http://haohaoxuexi.iteye.com/blog/2157769 本文使用Spring Security自带的方式连接数据库对用户进行认证. 1.Spring Se ...
随机推荐
- WSL2(Ubuntu)安装Docker
原文链接:https://www.cnblogs.com/blog5277/p/12071400.html 原文作者:博客园--曲高终和寡 *******************如果你看到这一行,说明 ...
- CSS3 clip-path & clip-path 打破矩形设计的限制
CSS 形状模块标准1(CSS Shapes Module Level 1)这个规范打破了 WEB 中的矩形盒模型的限制,并且将网页设计提升到一个新的高度. 关于 Shapes 规范 shape-ou ...
- FLUENT不同求解器离散格式选择【转载】
转载自:http://blog.163.com/wu_yangfeng/blog/static/16189737920104158950438/ 离散格式对求解器性能的影响 控制方程的扩散项一般采用中 ...
- 4、vueJs基础知识04
简单的目录结构: |-index.html |-main.js 入口文件 |-App.vue vue文件(组件),官方推荐命名法(首字母大写) |-components 组件存放的文件夹 | ...
- Java实现简单RPC框架(转)
一.RPC简介 RPC,全称Remote Procedure Call, 即远程过程调用,它是一个计算机通信协议.它允许像本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用).H ...
- eclipse如何配置tomcat
依次点击Window->Show View->Other 找到Server,点击OK,看到控制台旁边已有Server了. 点击server下面的链接,依次选择Apache,根据自己 ...
- Nexus3.X忘记admin密码找回
一.问题背景 nexus3 这种东西,传完一次,很少动了,很容易忘记密码,不要急有方法找回. 官方网站关于解决该问题的方法: https://support.sonatype.com/hc/en-us ...
- flutter Form表单
import 'package:flutter/material.dart'; class FormDemo extends StatelessWidget { @override Widget bu ...
- flutter chip标签组件
//一个Material widget. 它可以将一个复杂内容实体展现在一个小块中,如联系人.import 'package:flutter/material.dart'; class ChipDem ...
- Dart泛型
/* 通俗理解:泛型就是解决 类 接口 方法的复用性.以及对不特定数据类型的支持(类型校验) */ //只能返回string类型的数据 // String getData(String value){ ...