(三)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 ...
随机推荐
- DB2通过某列分组来去重
DB2通过某列分组来去重,可防止distinct对大字段的去重报错. row_number() OVER (PARTITION BY COL1 ORDER BY COL2) 表示根据COL1分组,在分 ...
- snprintf用错了快10年…
int snprintf(char *str, size_t size, const char *format, ...); 从用snprintf开始,size参数一直传的都是buff_size-1, ...
- 记Oracle中regexp_substr的一次调优(速度提高95.5%)
项目中需要做一个船舶代理费的功能,针对代理的船进行收费,那么该功能的第一步便是选择进行代理费用信息的录入,在进行船舶选择的时候,发现加载相关船舶信息十分的慢,其主要在sql语句的执行,因为测试的时候数 ...
- file_get_contents("php://input")
$data = file_get_contents("php://input"); php://input 是个可以访问请求的原始数据的只读流. POST 请求的情况下,最 ...
- 【转】python requests库添加自定义cookie的方法
requests库是个很方便的爬虫,相关文档已经很详细了.不过我今天在爬网页时,有一个网站是在脚本中添加cookie的,但我向requests.cookies里添加cookie费了不少周折.尝试了多个 ...
- springlcoud中使用consul作为注册中心
好久没写博客了,从今天开始重新杨帆起航............................................ springlcoud中使用consul作为注册中心. 我们先对比下注册 ...
- 改变jupyter notebook的主题背景
https://study.163.com/provider/400000000398149/index.htm?share=2&shareId=400000000398149( 欢迎关注博 ...
- iptables保存规则(ubuntu和centos)
1.Ubuntu 首先,保存现有的规则: iptables-save > /etc/iptables.rules 然后新建一个bash脚本,并保存到/etc/network/if-pre-up. ...
- cordova run android 可能遇到的错误解决
运行: ionic cordova build 等待下载,然后根据提示 输入android或者ios平台,即可 运行cordova run android 报错: 最快捷的解决方法就是使用Androi ...
- flutter 的Animation简单了解
import 'package:flutter/material.dart'; class AnimationDemo extends StatelessWidget { @override Widg ...