一、Spring Security是什么(百度百科)
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
二、初使用
Spring Security是自带登录页面的,所以我们可以直接使用它的页面,或者也可以自己编写页面。以下均使用框架自带的页面。
1. 用户在代码中自定义(无数据库版)
1.1 在yaml文件直接配置用户
spring:
security:
user:
name: user
password: 123
在yaml文件中直接配置如上所示的代码后就可以直接使用user账号登录了。
1.2 在代码中配置用户
我们可以通过继承WebSecurityConfigurerAdapter类来配置我们的用户,我们只要重写里面configure方法就可以了。
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启角色权限的注解
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin")//用户名
.password(passwordEncoder().encode("123456"))//密码加密
.roles("admin");//角色
auth.inMemoryAuthentication()
.withUser("user")//用户名
.password(passwordEncoder().encode("123"))//密码加密
.roles("normal");//角色
}
@Bean
public PasswordEncoder passwordEncoder(){
//将加密的类注册为bean
return new BCryptPasswordEncoder();
}
}
如上代码所示,你就注册了两个用户,admin和user。值得注意的是密码是要加密的,这里我选择了BCryptPasswordEncoder,并将其注册为bean。
还有这里的角色roles是指在控制器上的注解,如下图所示。
在使用上图的方法的时候,记得一定要开启@EnableGlobalMethodSecurity这个角色的权限注解。控制器的代码我就附在下面了。
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
@GetMapping("/helloAdmin")
@PreAuthorize("hasAnyRole('admin')")
public String helhelloAdminlo() {
return "hello,Admin";
}
@GetMapping("/helloNormal")
@PreAuthorize("hasAnyRole('normal','admin')")
public String helloNormal() {
return "hello,Normal";
}
}
2.连接数据库,通过数据库的用户来登录
使用数据的用户的话,我们可以继承UserDetailsService类,重写loadUserByUsername方法来实现。
package com.security.securitytest.config;
import com.security.securitytest.entity.Role;
import com.security.securitytest.entity.UserInfo;
import com.security.securitytest.service.UserService;
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.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.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@Component
public class MyUserDetailsService implements UserDetailsService {
@Resource
private UserService userServiceImpl;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("loadUserByUsername(String username)");
System.out.println("username="+username);
//这里通过自己写的服务层的方法获取用户信息
UserInfo userInfo = userServiceImpl.findUserByUsername(username);
if (userInfo == null){
//如果没有该用户就抛出"not found"信息
throw new UsernameNotFoundException("not found");
}
//创建一个权限的集合
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
//通过for循环获取用户里的角色信息
for(Role role : userInfo.getRoles()){
System.out.println("Role_"+role.getName());
//这里要注意我们需要在获取的角色名前加上"ROLE_",并且注意ROLE四个字母一定都要大写
authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getName()));
}
//创建用户信息,这里的user是引用org.springframework.security.core.userdetails.User类
User user = new User(userInfo.getUsername(),passwordEncoder.encode(userInfo.getPassword()),authorities);
return user;
}
}
这里附带一下我的实体类和数据库的设计方便说明。
首选是实体类的UserInfo和Role
1.UserInfo类
public class UserInfo {
private int id;
private String username;
private String password;
//这里我直接在用户的实体类里创建一个角色的List,我就不建pojo了,主要是懒,MyBatis啥的关联查询就自己写一下吧,我就不给了,应该不会有人不会写吧
private List<Role> roles;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
}
2.Role 类
public class Role {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
接着是数据设计的截图
1.user表
2. role表
3. user_role(角色用户表)