一般来说,我们的用户信息都是存放在数据库中的,本章节就基于数据库来完成认证与授权。
数据库设计
这里需要三张表:user(用户信息表)、role(角色表)、user_role(用户与角色关系表)。一般来说,角色与权限相关,所以用户具有什么样的角色,就拥有什么样的权限。
create table `user` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(50) NOT NULL,
`enabled` varchar(50) DEFAULT NULL,
`locked` varchar(50) DEFAULt NULL,
PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
create table `role` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
create table `user_role` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`uid` int NOT NULL,
`rid` int NOT NULL,
PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Maven依赖
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.9</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></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>2.1.3</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency>
application.yml配置文件
spring:
datasource:
url: jdbc:mysql://localhost:3306/world?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false&serverTimezone=UTC
type: com.alibaba.druid.pool.DruidDataSource
username: root
password: root
UserDetailsService的实现
UserDetailsService
是由Spring Security提供给我们的接口,如下所示。
publicinterfaceUserDetailsService{UserDetailsloadUserByUsername(String var1)throwsUsernameNotFoundException;}
我们可以自定义实现。
@ServicepublicclassUserServiceimplementsUserDetailsService{@AutowiredprivateUserMapper userMapper;@OverridepublicUserDetailsloadUserByUsername(String username)throwsUsernameNotFoundException{// 根据用户名查找用户User user= userMapper.loadUserByUsername(username);if(user==null){return user;}// 根据用户id查找所具有的角色List<Role> roles= userMapper.getUserRoleByUid(user.getId());
user.setRoles(roles);return user;}}
Mapper类
@MapperpublicinterfaceUserMapper{@Select("select * from user where username=#{username}")UserloadUserByUsername(String username);@Select("SELECT * FROM role r INNER JOIN user_role ur ON r.id = ur.rid WHERE uid=#{id}")List<Role>getUserRoleByUid(Integer id);}
实体类
Spring Security的用户都是用UserDetails
类代表。我们需要实现UserDetails
接口。
publicclassUserimplementsUserDetails{privateInteger id;privateString username;privateString password;privateBoolean enabled;privateBoolean locked;privateList<Role> roles;@OverridepublicCollection<?extendsGrantedAuthority>getAuthorities(){List<SimpleGrantedAuthority> authorities=newArrayList<>();for(Role role: roles){
authorities.add(newSimpleGrantedAuthority(role.getName()));}return authorities;}@OverridepublicStringgetPassword(){return password;}@OverridepublicStringgetUsername(){return username;}@OverridepublicbooleanisAccountNonExpired(){returntrue;}@OverridepublicbooleanisAccountNonLocked(){returntrue;}@OverridepublicbooleanisCredentialsNonExpired(){returntrue;}@OverridepublicbooleanisEnabled(){returntrue;}// getter or setter 省略}
WebSecurityConfigurerAdapter配置
@ConfigurationpublicclassUserWebSecurityConfigextendsWebSecurityConfigurerAdapter{@AutowiredprivateUserService userService;// 密码编码器,这里是明文,不对密码进行加密@BeanpublicPasswordEncoderpasswordEncoder(){returnnewPasswordEncoder(){@OverridepublicStringencode(CharSequence charSequence){return charSequence.toString();}@Overridepublicbooleanmatches(CharSequence charSequence,String s){return charSequence.toString().equals(s);}};}@Overrideprotectedvoidconfigure(HttpSecurity http)throwsException{
http.authorizeRequests().antMatchers("/admin/**").hasAnyRole("ADMIN").anyRequest().authenticated();}@Overrideprotectedvoidconfigure(AuthenticationManagerBuilder auth)throwsException{
auth.userDetailsService(userService);}}
备注
本系列都是学习《深入浅出Spring Security》的笔记