1.简绍
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
2.依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
3.认证模式
3-1实现Basic认证
Basic认证是一种较为简单的HTTP认证方式,客户端通过明文(Base64编码格式)传输用户名和密码到服务端进行认证,通常需要配合HTTPS来保证信息传输的安全。每当我们访问一个网页的时候,网站会弹出一个登录框,输入账号密码, 实现方式也很简单,只要写一个配置类。
依赖
<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-freemarker</artifactId>
</dependency>
配置类
package com.example.security.config;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.stereotype.Component;
@Component
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 新增security授权的账号 ,也可以理解为默认账号
*
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("admin").authorities("/");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//配置认证方式 token form 表单 设置httpBasic模式
http.authorizeRequests().antMatchers("/**").fullyAuthenticated().and().httpBasic();
}
/**
* There is no PasswordEncoder mapped for the id "null"
* 原因:升级为Security5.0以上密码支持多中加密方式,恢复以前模式
* @return
*/
@Bean
public static NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}
}
3-2form表单
要想 实现其实很简单,默认就是form表单,我们只要把这里改一下就OK了
4. 动态权限控制
简单说就是登录时 一个用户 通过数据库查询到对应的角色 ,对应角色有不同的权限 最后这个用户就能访问对应的网页了,
1.spring security的用户管需要实现UserDetailsService接口
2.我们登录需要在数据库查询这个用户是否真实存在,查询这个用户对应的权限
3.在开发 中我们的密码是加密 ,最简单的权限控制就完成了 我这里只展示核心代码
package com.example.security.config;
import com.example.security.service.MemberDetailsService;
import com.example.security.utills.MD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
@Component
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MemberDetailsService memberDetailsService;
/**
* 新增授权账户
*
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
/**
* 新增一个账户mayikt 密码也是为mayikt 可以允许访问所有的请求
*/
// auth.inMemoryAuthentication().withUser("mayikt").password("mayikt").authorities("mayikt");
/**
* 1.新增mayikt_admin mayikt_admin 权限可以访问所有请求
*/
auth.userDetailsService(memberDetailsService).passwordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence rawPassword) {
return MD5Util.encode((String) rawPassword);
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
//将加密的密码与数据库的对比
String rawPass = MD5Util.encode((String) rawPassword);
boolean result = rawPass.equals(encodedPassword);
return result;
}
});
}
}
package com.example.security.service;
import com.example.security.entity.PermissionEntity;
import com.example.security.entity.UserEntity;
import com.example.security.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.Component;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Component
public class MemberDetailsService implements UserDetailsService {
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
// 1.根据用户名称查询到user用户
UserEntity userDetails = userMapper.findByUsername(userName);
if (userDetails == null) {
return null;
}
// 2.查询该用户对应的权限
List<PermissionEntity> permissionList = userMapper.findPermissionByUsername(userName);
ArrayList<GrantedAuthority> grantedAuthorities = new ArrayList<>();
permissionList.forEach((a) -> {
grantedAuthorities.add(new SimpleGrantedAuthority(a.getPermTag()));
});
log.info(">>permissionList:{}<<", permissionList);
// 设置权限
userDetails.setAuthorities(grantedAuthorities);
return userDetails;
}
}
package com.example.security.utills;
import java.security.MessageDigest;
public class MD5Util {
private static final String SALT = "mayikt";
public static String encode(String password) {
password = password + SALT;
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
throw new RuntimeException(e);
}
char[] charArray = password.toCharArray();
byte[] byteArray = new byte[charArray.length];
for (int i = 0; i < charArray.length; i++)
byteArray[i] = (byte) charArray[i];
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
public static void main(String[] args) {
System.out.println(MD5Util.encode("mayikt"));
}
}