文章目录
文章目录
前言:AuthenticationProvider认证是由 AuthenticationManager 来管理的,但是真正进行认证的是
AuthenticationManager 中定义的
AuthenticationProvider。AuthenticationManager 中可以定义有多个
AuthenticationProvider。当我们使用 authentication-provider 元素来定义一个
AuthenticationProvider 时,如果没有指定对应关联的 AuthenticationProvider 对象,Spring
Security 默认会使用 DaoAuthenticationProvider。DaoAuthenticationProvider
在进行认证的时候需要一个 UserDetailsService 来获取用户的信息
UserDetails,其中包括用户名、密码和所拥有的权限等。所以如果我们需要改变认证的方式,我们可以实现自己的
AuthenticationProvider;如果需要改变认证的用户信息来源,我们可以实现 UserDetailsService。
1、pom文件中添加依赖
1、pom文件中添加依赖
导入 spring-boot-starter-security 依赖,在 SpringBoot 2.0 环境下默认使用的是 5.0 版本。Springboot版本为2.1.6
<dependencies>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
2、创建对应的user、role、user_role表
一般权限控制有三层,即:用户<–>角色<–>权限,用户与角色是多对多,角色和权限也是多对多,第一章我们先考虑用户和角色
1)、创建用户表(user)
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
2)、创建角色表role:
CREATE TABLE `role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) DEFAULT NULL,
`nameZh` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
3)、创建用户角色关系表user_role:
CREATE TABLE `user_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uid` int(11) NOT NULL,
`rid` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
初始化各个表数据供测试使用
INSERT INTO `user_role` VALUES (1,'1', '1');
INSERT INTO `user_role` VALUES (2,'2', '2');
INSERT INTO `role` VALUES ('1', 'ROLE_admin','管理员');
INSERT INTO `role` VALUES ('2', 'ROLE_user','普通用户');
INSERT INTO `user` VALUES ('1', 'admin', '123');
INSERT INTO `user` VALUES ('2', 'zhao', '123');
SpringSecurity规定权限格式为ROLE_xxx,一定要注意!!
3、登录页面和主页面
因为是比较简单的security程序,所以页面比较简单登录完成之后跳到home页面,页面位置在resource/static目录下:
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陆</title>
</head>
<body>
<h1>登陆</h1>
<form method="post" action="/login">
<div>
用户名:<input type="text" name="username">
</div>
<div>
密码:<input type="password" name="password">
</div>
<div>
<button type="submit">立即登陆</button>
</div>
</form>
</body>
</html>
home.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登陆成功</h1>
<a href="/admin">检测ROLE_ADMIN角色</a>
<a href="/user">检测ROLE_USER角色</a>
<button onclick="window.location.href='/logout'">退出登录</button>
</body>
</html>
4、配置application.properties
配置文件中简单配置数据库信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost/chapter03?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
mybatis.configuration.map-underscore-to-camel-case=true
5、创建entity、dao、service、controller
1)创建对应的实体User、Role、UserRole
public class User implements Serializable {
private Integer id;
private String username;
private String password;
//getset方法省略
}
public class Role implements Serializable {
private Integer id;
private String name;
private String nameZh;
//getset方法省略
}
public class UserRole implements Serializable {
private Integer id;
private Integer uid;
private Integer rid;
//getset方法省略
}
2)、创建对应的dao层UserMapper、RoleMapper、UserRoleMapper
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User selectById(Integer id);
@Select("SELECT * FROM user WHERE username = #{name}")
User selectByName(String name);
}
@Mapper
public interface RoleMapper {
@Select("SELECT * FROM role WHERE id = #{id}")
Role selectById(Integer id);
}
@Mapper
public interface UserRoleMapper {
@Select("SELECT * FROM user_role WHERE uid = #{uid}")
List<UserRole> listByUseId(Integer uid);
}
3)、创建对应的service:UserService 、RoleService 、UserRoleService
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User selectById(Integer id) {
return userMapper.selectById(id);
}
public User selectByName(String name) {
return userMapper.selectByName(name);
}
}
@Service
public class RoleService {
@Autowired
private RoleMapper roleMapper;
public Role selectById(Integer id) {
return roleMapper.selectById(id);
}
}
@Service
public class UserRoleService {
@Autowired
private UserRoleMapper userRoleMapper;
public List<UserRole> seletListByUserId(Integer uid) {
return userRoleMapper.listByUseId(uid);
}
}
4)、创建Controller
@Controller
public class LoginController {
@RequestMapping("/")
public String showHome() {
//获取当前用户名
String name = SecurityContextHolder.getContext().getAuthentication().getName();
System.out.println("当前用户为:------>" + name);
return "home.html";
}
@RequestMapping("/login")
public String login() {
return "login.html";
}
@RequestMapping("/admin")
@ResponseBody
@PreAuthorize("hasRole('ROLE_admin')") //判断用户是否有指定权限
public String printAdmin() {
return "如果你看见这句话,说明你有ROLE_admin角色";
}
@RequestMapping("/user")
@ResponseBody
@PreAuthorize("hasRole('ROLE_user')")
public String printUser() {
return "如果你看见这句话,说明你有ROLE_user角色";
}
}
6、配置SpringSecurity
1)、 UserDetailsService
实现UserDetailsService 接口,将用户信息和权限注入进来,需要重写 loadUserByUsername 方法,参数是用户输入的用户名。返回值是UserDetails,这是一个接口,一般使用它的子类org.springframework.security.core.userdetails.User,它有三个参数,分别是用户名、密码和权限集。
@Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserService userService;
@Autowired
private RoleService roleService;
@Autowired
private UserRoleService userRoleService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Collection<GrantedAuthority> authorities = new ArrayList<>();
User user = userService.selectByName(username);
// 判断用户是否存在
if(user == null) {
throw new UsernameNotFoundException("用户名不存在");
}
// 添加角色
List<UserRole> userRoles = userRoleService.seletListByUserId(user.getId());
for (UserRole userRole:userRoles) {
Role role = roleService.selectById(userRole.getRid());
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return new org.springframework.security.core.userdetails.User(user.getUsername(),user.getPassword(),authorities);
}
}
2)、WebSecurityConfig
该类是 Spring Security 的核心配置类,该类的三个注解分别:
@Configuration//该类是配置类
@EnableWebSecurity//开启 Security 服
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启全局 Securtiy 注解。
具体实现:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(charSequence.toString());
}
});
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login")
// 设置登陆成功页
.defaultSuccessUrl("/").permitAll()
.and()
// 自定义登陆用户名和密码参数,默认为username和password
// .usernameParameter("username")
// .passwordParameter("password")
.logout()
.permitAll();
http.csrf().disable();
}
@Override
public void configure(WebSecurity web) throws Exception {
// 设置拦截忽略文件夹,可以对静态资源放行
web.ignoring().antMatchers("/css/**", "/js/**");
}
}
程序启动成功就可以分别登陆,查看此用户属于哪种权限
鸣谢: https://blog.youkuaiyun.com/yuanlaijike/article/details/80249235