SpringCloud-Secruity入门开发(用户以及权限从数据库查)

在用户以及权限硬编码的基础上整改,将用户以及用户的权限修改成从数据库查询.

硬编码教程SpringCloud-Secruity入门开发(用户以及权限硬编码篇)

具体实现

添加依赖

新增mybatis的依赖,链接数据库的mysql驱动依赖以及lombok的依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.15.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.nlx</groupId>
	<artifactId>springcloud-security</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springcloud-security</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

        <!-- mybatis依赖-->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.3</version>
		</dependency>

        <!--mysql驱动-->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
        <!--lombok依赖-->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

lombok只是为了待会儿pojo类不用 写getter以及setter等方法而添加的工具插件,不是必须有的依赖.

数据库创建用户及权限表

为了图省事,这里只创建一个用户表,但是表里包含了权限,实际开发中一般不这么做,而是将用户跟权限分开做绑定

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `password` varchar(64) DEFAULT NULL,
  `authruity` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

创建pojo/mapper/mapper.xml
user.java

package com.nlx.pojo;

import java.io.Serializable;

import lombok.Data;

@Data
public class User implements Serializable{

	private static final long serialVersionUID = 1L;

	private int id;
	
	private String name;
	
	private String password;
	
	private String authruity;
}

UserMapper.java

package com.nlx.mapper;

import org.apache.ibatis.annotations.Mapper;

import com.nlx.pojo.User;

@Mapper
public interface UserMapper {

	User selectByName(String username);
}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nlx.mapper.UserMapper">
  
   <select id="selectByName" resultType="com.nlx.pojo.User" >
     select * from user where name=#{username}
   </select>
 
</mapper>

 

配置数据链接 以及mybatis的包扫描和mapper.xml位置

mybatis.mapper-locations=classpath:mapper/*Mapper.xml
mybatis.type-aliases-package=com.nlx.pojo

spring.datasource.username=root
spring.datasource.password=nlx@123
spring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

 

新建service.impl包,并在包里新建实现类,实现UserDetailsService接口

package com.nlx.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import com.nlx.mapper.UserMapper;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class MyUserDetailsService implements UserDetailsService {

	@Autowired
	private UserMapper userMapper;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

		// 从数据库查询用户
		com.nlx.pojo.User selectByName = userMapper.selectByName(username);
		log.info("用戶名:" + username);
		// 如果用户不为null
		if (selectByName != null) {
			log.info("用戶名权限:" + selectByName.getAuthruity());
			log.info("用戶密码:" + selectByName.getPassword());
			// 这里的user是org.springframework.security.core.userdetails.User;
			return new User(username, selectByName.getPassword(),
					AuthorityUtils.commaSeparatedStringToAuthorityList(selectByName.getAuthruity()));
			//return new User(username, selectByName.getPassword(),
			//		多个权限的格式
			//		AuthorityUtils.commaSeparatedStringToAuthorityList("p1,p2,p3"));
		}
		// 如果没有这个用户 返回null 由secruity处理异常
		return null;
	}

}

 注入UserMapper从数据库根据用户名查密码以及权限,然后将用户名,密码,权限赋值给UserDetails的子类
org.springframework.security.core.userdetails.User里面 返回就可以,当有多个权限时,用逗号隔开,

配置类MyWebSecruityConfig需要修改的地方如下

package com.nlx.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class MyWebSecruityConfig extends WebSecurityConfigurerAdapter{

	@Override
	protected void configure(HttpSecurity http) throws Exception {
			http
				// 关闭csrf
				.csrf().disable()
				.authorizeRequests()
				// 添加权限
				.antMatchers("/insert").hasAuthority("p1")
				.antMatchers("/delete").hasAuthority("p2")
				// 其他不匹配上面的验证规则的请求都需要被验证
				.anyRequest().authenticated()
				// permitAll()无条件允许访问
				// 开启session管理
				// .and().sessionManagement()
				.and().logout()
				// 基本认证
				// .and().httpBasic();
				// 表单认证
				.and().formLogin();
	}

	/*
	@Bean
	protected UserDetailsService userDetailsService() {
		InMemoryUserDetailsManager im = new InMemoryUserDetailsManager();
		im.createUser(User.withUsername("zhansan").password("123").authorities("p1").build());
		im.createUser(User.withUsername("lisi").password("123").authorities("p2").build());
		return im;
	}*/
	 
	@Bean
	PasswordEncoder passwordEncoder() {
		/**
		 * 	secriuty默认对密码进行了BCrypt加密
		 * 	我们这里暂时不加密密码
		 */
		//return new BCryptPasswordEncoder();
		return NoOpPasswordEncoder.getInstance();
	}
}

注释或者删除userDetailsService方法即可。

测试
数据库添加用户及权限

重启项目

 由上图可以看出我们给用户test分配了p1权限,而访问/delete需要p2权限,如果test用户访问不到/delete,但是能访问到其他的接口则表示我们的配置是ok的
浏览器访问http://localhost:8080/delete,跳转登录后的访问结果如下。

其他三个接口的访问结果如下 

 
总结

在上面的4个步骤中只有第四步是核心,简单概括就是添加一个实现类MyUserDetailsService实现UserDetailsService接口
并重写方法 loadUserByUsername(String username)我们在这个方法里面去查数据库返回密码以及权限封装给
org.springframework.security.core.userdetails.User返回即可,至于验证的过程交给Secruity去做。这里添加了这个实现,就需要我们删除在配置文件写死在内存中的用户。
关于密码加密问题:
secruity默认使用的加密是BCryptPasswordEncoder加密,如果配置文件中配置了加密方式(一定要配置加密方式),相对应的 如果我们存在数据库的密码是明文,则返回验证的时候需要手动加密,否则匹配不上会一直报密码或用户名错误。

package com.nlx.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class MyWebSecruityConfig extends WebSecurityConfigurerAdapter{

	@Override
	protected void configure(HttpSecurity http) throws Exception {
			http
				// 关闭csrf
				.csrf().disable()
				.authorizeRequests()
				// 添加权限
				.antMatchers("/insert").hasAuthority("p1")
				.antMatchers("/delete").hasAuthority("p2")
				// 其他不匹配上面的验证规则的请求都需要被验证
				.anyRequest().authenticated()
				// permitAll()无条件允许访问
				// 开启session管理
				// .and().sessionManagement()
				.and().logout()
				// 基本认证
				// .and().httpBasic();
				// 表单认证
				.and().formLogin();
	}
	 
        //这个bean不能少否则后台报错
	@Bean
	PasswordEncoder passwordEncoder() {
		//secriuty默认对密码进行了BCrypt加密
		return new BCryptPasswordEncoder();
	}
}

如果我们配置文件对密码加密配置为BCryptPasswordEncoder,那么在MyUserDetailsService中就需要对密码进行加密(因为我们存数据库的密码是明文的,不是BCryptPasswordEncoder加密的)

package com.nlx.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import com.nlx.mapper.UserMapper;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class MyUserDetailsService implements UserDetailsService {

	@Autowired
	private UserMapper userMapper;

//注入配置文件密码加密的bean
	@Autowired
	private PasswordEncoder encode;
	
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		com.nlx.pojo.User selectByName = userMapper.selectByName(username);
		log.info("用戶名:" + username);

		if (selectByName != null) {
			log.info("用戶名权限:" + selectByName.getAuthruity());
			log.info("用戶密码:" + selectByName.getPassword());
			// 在这里的密码进行加密
			return new User(username, encode.encode(selectByName.getPassword()),
		AuthorityUtils.commaSeparatedStringToAuthorityList(selectByName.getAuthruity()));	
		}
		return null;
	}

}

修改的地方是注入的配置文件里面创建的用于密码加密的bean以及将数据库查出来的明文密码进行加密后再封装。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值