SpringBoot整合Spring Security,使用数据库鉴权(四)
一、实现UserDetails接口
package com.example.securityzimug.config.auth;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
public class MyUserDetails implements UserDetails {
String password; //密码
String username; //用户名
boolean accountNonExpired; //是否没过期
boolean accountNonLocked; //是否没被锁定
boolean credentialsNonExpired; //是否没过期
boolean enabled; //账号是否可用
Collection<? extends GrantedAuthority> authorities; //用户的权限集合
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
public void setPassword(String password) {
this.password = password;
}
public void setUsername(String username) {
this.username = username;
}
public void setAccountNonExpired(boolean accountNonExpired) {
this.accountNonExpired = accountNonExpired;
}
public void setAccountNonLocked(boolean accountNonLocked) {
this.accountNonLocked = accountNonLocked;
}
public void setCredentialsNonExpired(boolean credentialsNonExpired) {
this.credentialsNonExpired = credentialsNonExpired;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
this.authorities = authorities;
}
}
二、编写mapper
在编写之前需要导入依赖。
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
package com.example.securityzimug.config.auth;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface MyUserDetailsServiceMapper {
//根据userID查询用户信息
@Select("SELECT username,password,enabled\n" +
"FROM sys_user u\n" +
"WHERE u.username = #{userId} or u.phone = #{userId}")
MyUserDetails findByUserName(@Param("userId") String userId);
//根据userID查询用户角色列表
@Select("SELECT role_code\n" +
"FROM sys_role r\n" +
"LEFT JOIN sys_user_role ur ON r.id = ur.role_id\n" +
"LEFT JOIN sys_user u ON u.id = ur.user_id\n" +
"WHERE u.username = #{userId} or u.phone = #{userId}")
List<String> findRoleByUserName(@Param("userId") String userId);
//根据用户角色查询用户权限
@Select({
"<script>",
"SELECT url " ,
"FROM sys_menu m " ,
"LEFT JOIN sys_role_menu rm ON m.id = rm.menu_id " ,
"LEFT JOIN sys_role r ON r.id = rm.role_id ",
"WHERE r.role_code IN ",
"<foreach collection='roleCodes' item='roleCode' open='(' separator=',' close=')'>",
"#{roleCode}",
"</foreach>",
"</script>"
})
List<String> findAuthorityByRoleCodes(@Param("roleCodes") List<String> roleCodes);
}
三、实现UserDetailsService接口
package com.example.securityzimug.config.auth;
import org.springframework.security.core.authority.AuthorityUtils;
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 javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author baikunlong
* @date 2020/9/22 23:14
*/
@Component
public class MyUserDetailsService implements UserDetailsService {
@Resource
private MyUserDetailsServiceMapper myUserDetailsServiceMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
MyUserDetails myUserDetails = myUserDetailsServiceMapper.findByUserName(username);
//角色集合
List<String> roleList = myUserDetailsServiceMapper.findRoleByUserName(username);
//资源权限集合
List<String> authorities = myUserDetailsServiceMapper.findAuthorityByRoleCodes(roleList);
//角色是特殊的权限,前缀规定为ROLE_
roleList=roleList.stream().map(role->"ROLE_"+role).collect(Collectors.toList());
authorities.addAll(roleList);
myUserDetails.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList(String.join(",",authorities)));
return myUserDetails;
}
}
四、修改配置类
注意这里的UserDetailsService一定要使用注入方式,我一开始手动new的,这会导致mapper为空,在service那排错了很久,后来才发现是这边的问题。
五、修改配置文件
spring:
security:
# 用数据库后,内存模式的就先注释掉吧
# user:
# name: admin
# password: admin
loginType: JSON
datasource:
url: jdbc:mysql://localhost:3306/study_springboot_05_security_zimug?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: '123456'
driver-class-name: com.mysql.cj.jdbc.Driver
#logging:
# level:
# root: debug
需要注意的是,配置文件如果是yml文件类型的,密码一定要加单引号或者双引号,不然连接不了数据库的,properties不存在这个问题。
六、动态鉴权
在一开始我们的鉴权都是写的静态的,当有新需求时可能会更改代码,所以需要动态的鉴权。
编写一个类来鉴权。
package com.example.securityzimug.config.auth;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
@Component("rabcService")
public class MyRBACService {
/**
* 判断某用户是否具有该request资源的访问权限
*/
public boolean hasPermission(HttpServletRequest request, Authentication authentication){
//这个就是UserDetails
Object principal = authentication.getPrincipal();
if(principal instanceof UserDetails){
UserDetails userDetails = ((UserDetails)principal);
//这里的请求地址就是资源权限名
List<GrantedAuthority> authorityList =
AuthorityUtils.commaSeparatedStringToAuthorityList(request.getRequestURI());
//判断当前用户是否有这个资源权限
return userDetails.getAuthorities().contains(authorityList.get(0));
}
return false;
}
}
然后在配置类里更改下权限配置:
还没有评论,来说两句吧...