首先是依赖
springboot是2.1.9 springsecurity是5.1.6
<?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.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.song</groupId>
<artifactId>springsecuritydemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springsecuritydemo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.20</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
<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.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置文件
主要是配置数据源信息和指定*Mapper.xml文件的配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/springsecuritydemo?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=qjfy
mybatis.mapper-locations=classpath:/mapper/*.xml
数据库
有三张表 分别是role、user、user_role
实体类
springsecurity要求创建的user类实现UserDetails类并重写其中的方法
User.java
public class User implements UserDetails {
private Integer id;
private String username;
private String password;
private boolean enabled;
private boolean locked;
private List<Role> roles;
//将该用户的角色信息存入这个集合中
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> list = new ArrayList<>();
for (Role role : roles) {
list.add(new SimpleGrantedAuthority(role.getName()));
}
return list;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
//判断账户是否没有过期
@Override
public boolean isAccountNonExpired() {
return true;
}
//判断账户是否没有被锁
@Override
public boolean isAccountNonLocked() {
return !locked;
}
//判断当前账户密码是否没有过期
@Override
public boolean isCredentialsNonExpired() {
return true;
}
//判断当前账户是否可用
@Override
public boolean isEnabled() {
return enabled;
}
//省略getter和setter方法
Role.java
@Data
public class Role {
private Integer id;
private String name;
private String nameZh;
}
springsecurity要求创建的UserService需要实现UserDetailsService并实现其中的loadUserByUsername方法。
UserService.java
@Service("userService")
public class UserServiceImpl implements UserDetailsService {
@Autowired
UserMapper userMapper;
//通过查询数据库加载登陆用户的信息,在用户登陆时自动调用
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
//加载用户信息
User user = userMapper.loadUserByUsername(s);
if(user == null){
throw new UsernameNotFoundException("账户不存在");
}
//通过用户id在数据库中查询该用户的所有角色信息,并存入user对象中
user.setRoles(userMapper.getRolesByUserId(user.getId()));
//返回的user对象会由后续的DaoAuthenticationProvider类去对比登陆的密码是否正确
return user;
}
}
UserMapper.java 和 UserMapper.xml
@Repository("userMapper")
public interface UserMapper {
User loadUserByUsername(String s);
List<Role> getRolesByUserId(Integer id);
}
<?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.song.springsecuritydemo.mapper.UserMapper">
<select id="loadUserByUsername" resultType="com.song.springsecuritydemo.pojo.User">
select * from user where username=#{username};
</select>
<select id="getRolesByUserId" resultType="com.song.springsecuritydemo.pojo.Role">
select * from role r ,user_role ur where r.id=ur.rid and ur.uid=#{id};
</select>
</mapper>
配置springsecurity
springsecurity 5.x以后,不需要开发者指定加密方式,在数据库中存储密码的时候指定加密方式即可:({bcrypt}$2a 10 10 10IJiwCaDbDpWgLcFD/G1Dd.DUAAZXIL99kaa3Op1zS4pvypPe4Ft/6),并按如下passwordEncoder()方法即可。PasswordEncoderFactorids这个类中集成了很多的加密方式,在对比密码时根据密码前的加密方式id再选择对应的加密方法对象。如果在数据库中没有指定id,就会报错:There is no PasswordEncoder mapped for the id “null”。
@Configuration
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserServiceImpl userService;
//密码加密
@Bean
PasswordEncoder passwordEncoder(){
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
//指定UserService
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
//基于Url的授权
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/db/**").hasRole("dba")
.antMatchers("/user/**").hasRole("user")
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/login").permitAll()
.and()
.csrf().disable();
}
}
授权方式除了url授权还有基于注解方式的授权。在springsecurity的配置类上加注解:@EnableGlobalMethodSecurity。在service的方法上加上@Secured或@preAuthorize注解并配置权限即可。
最后创建controller就可以验证认证授权了。