配置 Druid 数据源

配置 Druid 数据源,看下这篇博客,至于后面的添加监控那些就不用看了,仅仅看如何整合的 ;


数据库

需要创建 userrolerole_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 从数据库中检索用户名和密码的更多相关文章

  1. spring security进阶 使用数据库中的账户和密码认证

    目录 spring security 使用数据库中的账户和密码认证 一.原理分析 二.代码实现 1.新建一个javaWeb工程 2.用户认证的实现 3.测试 三.总结 spring security ...

  2. Spring Security使用数据库数据完成认证--练气后期2

    写在前面 没错,这篇文章还是练气后期!但作者我相信筑基指日可待! 在前一篇文章当中,我们简单地分析了一下Spring Security的认证流程,知道了如果想要实现对自己用户数据(账户.角色.权限)的 ...

  3. Spring Security 3.1 中功能强大的加密工具 PasswordEncoder

    Spring Security 3.1 中功能强大的加密工具 PasswordEncoder 博客分类: security spring springsecurity  好吧,这种加密机制很复杂,还是 ...

  4. git 中添加用户名和密码

    git 中添加用户名和密码:https://blog.csdn.net/qq_28602957/article/details/52154384 在使用git时,如果用的是HTTPS的方式,则每次提交 ...

  5. spring security结合数据库验证用户-XML配置方式

    之前的用户信息我们都是使用的内存用户,测试例子可以,实际中使用肯定不行,需要结合数据库进行验证用户.这就是本节的重点: 项目目录如下:  在之前的项目中的依赖中添加两个依赖: <dependen ...

  6. spring security使用数据库资源

    国内对权限系统的基本要求是将用户权限和被保护资源都放在数据库里进行管理,在这点上Spring Security并没有给出官方的解决方案,为此我们需要对Spring Security进行扩展.. 数据库 ...

  7. spring security使用数据库验证的逻辑处理

    前面做了多个示例,包括使用jdbc和hibernate两种方式访问数据库获取用户信息和权限信息,其中一些关键步骤如下:   我们在SecurityConfig中配置覆盖configure方法时候,可以 ...

  8. spring boot系列--spring security (基于数据库)登录和权限控制

    先说一下AuthConfig.java Spring Security的主要配置文件之一 AuthConfig 1 @Configuration 2 @EnableWebSecurity 3 publ ...

  9. Spring Security 使用数据库用户进行认证

    本文参考或摘录自:http://haohaoxuexi.iteye.com/blog/2157769 本文使用Spring Security自带的方式连接数据库对用户进行认证. 1.Spring Se ...

随机推荐

  1. iframe中用到的例子

    <view:qrytr>         <view:qrytd colspan="4">     <iframe id="ccbl&quo ...

  2. boosting与随机森林

      本文原创,转载请注明出处 http://www.cnblogs.com/gufeiyang 本文主要分两部分,boosting 与 随机森林. “三个臭皮匠顶一个诸葛亮”是说三个不聪明的人集合在一 ...

  3. 【Python 代码】CS231n中Softmax线性分类器、非线性分类器对比举例(含python绘图显示结果)

    1 #CS231n中线性.非线性分类器举例(Softmax) #注意其中反向传播的计算 # -*- coding: utf-8 -*- import numpy as np import matplo ...

  4. locust使用命令

    locust -f locust_demo.py --logfile=locusfile.log

  5. php异步处理

    <?php namespace Index\Controller; use Core\Controller; class test extends Controller { public fun ...

  6. QEMU支持的网络模式

    网络是现代计算机系统不可或缺的一部分,QEMU也对虚拟机提供丰富的网络支持.qemu-kvm中主要给客户机提供了如下4种不同模式的网络. (1)基于网桥(Bridge)的虚拟网卡 (2)基于NAT(N ...

  7. Flutter: 运行新项目报错

    今天接手了一个客户传过来的Flutter项目,估计是客户直接拷贝过来的,无法直接运行,由于刚接手Flutter, 很多东西还不懂,折腾了一会给弄好了. 1. 提示Dart SDK is not con ...

  8. Dart静态方法、对象操作符和类的继承

    /* Dart中的静态成员: 1.使用static 关键字来实现类级别的变量和函数 2.静态方法不能访问非静态成员,非静态方法可以访问静态成员 */ // class Person { // stat ...

  9. openresty开发系列20--lua的时间操作

    openresty开发系列20--lua的时间操作 在 Lua 中,函数 time.date 和 difftime 提供了所有的日期和时间功能.在 OpenResty 的世界里,不推荐使用这里的标准时 ...

  10. linux非root用户安装5.7.27版本mysql

    先下安装包,到mysql官网https://dev.mysql.com/downloads/mysql/选好安装包版本.操作系统类型(默认是最新版本,点击右边链接Looking for previou ...