1、配置用户,即创建个人用户凭据和所属角色
/** * 配置用户 * 验证用户的机制,并返回正在验证的用户的信息 */ @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled=true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { /** * 使用 Security 认证管理器 * @return * @throws Exception */ @Override @Bean public AuthenticationManager authenticationManager() throws Exception { return super.authenticationManager(); } /** * security 密码加密 * @return */ @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean @Override public UserDetailsService userDetailsService() { return new UserDetailsServiceImpl(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService()); } /** * 配置security不拦截的请求 * 将check_token暴露出去,否则资源服务器访问时报403错误 * @param web * @throws Exception */ @Override public void configure(WebSecurity web) throws Exception { web.ignoring() .antMatchers("/auth/login", "/oauth/check_token"); } @Override public void configure(HttpSecurity http) throws Exception { //禁止跨域请求 http.csrf().disable() .httpBasic() .and() .formLogin() .and() .authorizeRequests().anyRequest().authenticated(); } }
2、自定义用户认证与授权
/** * 自定义用户认证与授权 * @author suoyx * @date 2021/3/21 19:06 */ public class UserDetailsServiceImpl implements UserDetailsService { @Resource private AuthUserService authUserService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { AuthUser authUser = authUserService.findByUserName(username); // 用户权限 Set<GrantedAuthority> grantedAuthorities = new HashSet<>(); List<Menu> menuList = authUserService.listMenuByUserId(authUser.getId()); menuList.forEach(SysMenu -> { if (StringUtils.isNotBlank(SysMenu.getResource())) { GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(SysMenu.getResource()); grantedAuthorities.add(grantedAuthority); } }); // 构建返回信息 JwtUser jwtUser = new JwtUser(authUser.getUserName(), authUser.getPassword(), grantedAuthorities); jwtUser.setId(authUser.getId()); jwtUser.setUsername(authUser.getUserName()); return jwtUser; } }
3、自定义用户认证与授权
UserDetailsServiceImpl类实现UserDetailsService接口,重写loadUserByUsername方法
public class UserDetailsServiceImpl implements UserDetailsService { @Resource private AuthUserService authUserService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { AuthUser authUser = authUserService.findByUserName(username); // 用户权限 Set<GrantedAuthority> grantedAuthorities = new HashSet<>(); List<Menu> menuList = authUserService.listMenuByUserId(authUser.getId()); menuList.forEach(SysMenu -> { if (StringUtils.isNotBlank(SysMenu.getResource())) { GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(SysMenu.getResource()); grantedAuthorities.add(grantedAuthority); } }); // 构建返回信息 JwtUser jwtUser = new JwtUser(authUser.getUserName(), authUser.getPassword(), grantedAuthorities); jwtUser.setId(authUser.getId()); jwtUser.setUsername(authUser.getUserName()); return jwtUser; } }
自定义用户信息:
@Data public class JwtUser extends User { private Long id; private String username; public JwtUser(String username, String password, Collection<? extends GrantedAuthority> authorities) { super(username, password, authorities); } }
用户和权限相关的接口和实现类:
public interface AuthUserService { /** * 根据用户名查询当前用户是否存在 * @param name * @return */ AuthUser findByUserName(String name); /** * 根据用户id查询当前用户拥有的权限 * @param userId 用户id * @return */ List<Menu> listMenuByUserId(long userId); }
@Service public class AuthUserServiceImpl implements AuthUserService { @Autowired AuthUserMapper authUserMapper; @Autowired UserRoleMapper userRoleMapper; @Autowired RoleMenuMapper roleMenuMapper; @Autowired private MenuMapper menuMapper; @Override public AuthUser findByUserName(String name) { LambdaQueryWrapper<AuthUser> lambda = new QueryWrapper<AuthUser>().lambda(); lambda.eq(AuthUser::getUserName, name); return authUserMapper.selectOne(lambda); } @Override public List<Menu> listMenuByUserId(long userId) { // 筛选出所有的角色id LambdaQueryWrapper<UserRole> lambda = new QueryWrapper<UserRole>().lambda(); lambda.eq(UserRole::getAuthUserId, userId); List<UserRole> roleUsers = userRoleMapper.selectList(lambda); // 筛选出所有的角色id List<Long> roleIds = roleUsers.stream().map(UserRole::getRoleId).collect(Collectors.toList()); //根据角色来查询对应的菜单 LambdaQueryWrapper<RoleMenu> roleWrapper = new QueryWrapper<RoleMenu>().lambda(); roleWrapper.in(RoleMenu::getRoleId, roleIds); List<RoleMenu> menuList = roleMenuMapper.selectList(roleWrapper); //筛选所有的权限id List<Long> menu = menuList.stream().map(RoleMenu::getMenuId).collect(Collectors.toList()); LambdaQueryWrapper<Menu> menuWrapper = new QueryWrapper<Menu>().lambda(); menuWrapper.in(Menu::getId, menu); menuWrapper.eq(Menu::getLogicalDeleted, 1); return menuMapper.selectList(menuWrapper); } }
对应的Mapper和Entity实体:
@Repository public interface AuthUserMapper extends BaseMapper<AuthUser> { }
@Repository public interface MenuMapper extends BaseMapper<Menu> { }
@Repository public interface RoleMenuMapper extends BaseMapper<RoleMenu> { }
@Repository public interface UserRoleMapper extends BaseMapper<UserRole> { }
实体类:
个人账号实体类:
@Data @TableName(value = "user") public class AuthUser extends BaseModel { /** * 主键 */ @TableId(value = "id", type = IdType.AUTO) private Long id; /** * 用户名称 */ @TableField(value = "user_name") private String userName; /** * 用户密码 */ @TableField(value = "password") private String password; /** * 手机号 */ @TableField(value = "mobile_phone") private String mobilePhone; /** * 用户状态1.启用2.禁用 */ @TableField(value = "state") private Byte state; /** * 微信openid */ @TableField(value = "open_id") private String openId; /** * 过期时间 */ @TableField(value = "expire_time") private Date expireTime; }
菜单实体类: @Data @TableName(value = "menu") public class Menu extends BaseModel { /** * 主键 */ @TableId(value = "id", type = IdType.AUTO) private Long id; /** * 菜单和API接口名称 */ @TableField(value = "title") private String title; /** * 路径 */ @TableField(value = "path") private String path; /** * 图标 */ @TableField(value = "icon") private String icon; /** * 类型1.菜单2.API接口 */ @TableField(value = "type") private Byte type; /** * 按钮显示code */ @TableField(value = "code") private String code; /** * 父级菜单id */ @TableField(value = "parent_id") private Long parentId; /** * 是否是系统菜单1.是2.不是 */ @TableField(value = "is_system_menu") private Byte isSystemMenu; /** * 权限码 */ @TableField(value = "resource") private String resource; /** * 排序号 */ @TableField(value = "sort") private Long sort; }
角色和菜单关系类: @Data @TableName(value = "role_menu") public class RoleMenu extends BaseModel { /** * 主键 */ @TableId(value = "id", type = IdType.INPUT) private Long id; /** * 角色id */ @TableField(value = "role_id") private Long roleId; /** * 菜单和API接口id */ @TableField(value = "menu_id") private Long menuId; }
用户和角色关系实体类:
@Data @TableName(value = "user_role") public class UserRole extends BaseModel { /** * 主键 */ @TableId(value = "id", type = IdType.AUTO) private Long id; /** * 用户账号id */ @TableField(value = "auth_user_id") private Long authUserId; /** * 角色id */ @TableField(value = "role_id") private Long roleId; }
4、准备数据
/*
Navicat MySQL Data Transfer
Source Server : localhost_3306
Source Server Version : 50625
Source Host : localhost:3306
Source Database : springcloud
Target Server Type : MYSQL
Target Server Version : 50625
File Encoding : 65001
Date: 2021-03-28 23:10:39
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `menu`
-- ----------------------------
DROP TABLE IF EXISTS `menu`;
CREATE TABLE `menu` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`title` varchar(50) NOT NULL COMMENT '菜单或者按钮名称',
`path` varchar(255) NOT NULL COMMENT '路径',
`icon` varchar(255) NOT NULL COMMENT '图标',
`type` tinyint(4) unsigned NOT NULL COMMENT '类型1.菜单2.按钮3.元素',
`code` varchar(50) NOT NULL DEFAULT '' COMMENT '按钮显示code',
`parent_id` bigint(20) NOT NULL COMMENT '父级菜单id',
`is_system_menu` tinyint(4) unsigned NOT NULL COMMENT '是否是系统菜单1.是2.不是(业务菜单)',
`resource` varchar(255) NOT NULL DEFAULT '' COMMENT '权限',
`sort` tinyint(4) NOT NULL COMMENT '排序',
`create_by` bigint(20) NOT NULL COMMENT '创建人id',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`last_modify_by` bigint(20) NOT NULL COMMENT '上次修改人id',
`last_modify_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '上次修改时间',
`logical_deleted` tinyint(4) NOT NULL DEFAULT '1' COMMENT '逻辑删除1.正常2.已删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Records of menu
-- ----------------------------
INSERT INTO `menu` VALUES ('1', '库存分析', '/1', '1', '1', '1', '0', '1', '1', '0', '1', '2021-01-29 15:03:08', '1', '2021-01-29 15:03:08', '0');
INSERT INTO `menu` VALUES ('2', '订单分析', '/2', '2', '1', '1', '0', '1', '2', '0', '1', '2021-01-29 15:03:08', '1', '2021-01-29 15:03:08', '0');
INSERT INTO `menu` VALUES ('3', '后台管理', '/3', '3', '1', '1', '0', '1', '3', '0', '1', '2021-01-29 15:03:08', '1', '2021-01-29 15:03:08', '0');
INSERT INTO `menu` VALUES ('4', '库存数量', '/4', '4', '1', '1', '1', '1', '4', '0', '1', '2021-01-29 15:03:08', '1', '2021-01-29 15:03:08', '0');
INSERT INTO `menu` VALUES ('5', '库存总额', '/5', '4', '1', '1', '1', '1', '5', '0', '1', '2021-01-29 15:03:08', '1', '2021-01-29 15:03:08', '0');
INSERT INTO `menu` VALUES ('6', '库存信息', '/6', '4', '1', '1', '1', '1', '6', '0', '1', '2021-01-29 15:03:08', '1', '2021-01-29 15:03:08', '0');
-- ----------------------------
-- Table structure for `oauth_client_details`
-- ----------------------------
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
`client_id` varchar(128) NOT NULL,
`resource_ids` varchar(256) DEFAULT NULL,
`client_secret` varchar(256) DEFAULT NULL,
`scope` varchar(256) DEFAULT NULL,
`authorized_grant_types` varchar(256) DEFAULT NULL,
`web_server_redirect_uri` varchar(256) DEFAULT NULL,
`authorities` varchar(256) DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL,
`refresh_token_validity` int(11) DEFAULT NULL,
`additional_information` varchar(4096) DEFAULT NULL,
`autoapprove` varchar(256) DEFAULT NULL,
PRIMARY KEY (`client_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Records of oauth_client_details
-- ----------------------------
INSERT INTO `oauth_client_details` VALUES ('client', null, '$2a$10$rfjh0xBSbAih956yoisDFOFKVNjJzByET0ShRNzVs9M9oqQQlvjki', 'web', 'authorization_code,password,refresh_token,client_credentials', '', null, null, null, null, 'true');
-- ----------------------------
-- Table structure for `role`
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(32) NOT NULL COMMENT '角色名称',
`description` varchar(255) NOT NULL COMMENT '部门简述',
`state` tinyint(4) unsigned NOT NULL COMMENT '角色状态1.启用2.禁用',
`type` tinyint(4) DEFAULT NULL COMMENT '1.后台2.前台',
`create_by` bigint(20) DEFAULT NULL COMMENT '创建人id',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`last_modify_by` bigint(20) DEFAULT NULL COMMENT '上次修改人id',
`last_modify_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '上次修改时间',
`logical_deleted` tinyint(4) DEFAULT '1' COMMENT '逻辑删除1.正常2.已删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES ('1', '角色1', '角色1', '1', '1', '2', '2021-01-29 15:03:08', '2', '2021-01-29 15:03:08', '0');
INSERT INTO `role` VALUES ('2', '角色2', '角色2', '1', '1', '2', '2021-01-29 15:03:08', null, '2021-01-29 15:03:08', '0');
INSERT INTO `role` VALUES ('3', '角色3', '角色3', '1', '1', '2', '2021-01-29 15:03:08', '2', '2021-01-29 15:03:08', '0');
-- ----------------------------
-- Table structure for `role_menu`
-- ----------------------------
DROP TABLE IF EXISTS `role_menu`;
CREATE TABLE `role_menu` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`role_id` bigint(20) unsigned NOT NULL COMMENT '角色id',
`menu_id` bigint(20) unsigned NOT NULL COMMENT '菜单或者按钮id',
`create_by` bigint(20) NOT NULL COMMENT '创建人id',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`last_modify_by` bigint(20) NOT NULL COMMENT '上次修改人id',
`last_modify_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '上次修改时间',
`logical_deleted` tinyint(4) NOT NULL DEFAULT '1' COMMENT '逻辑删除1.正常2.已删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Records of role_menu
-- ----------------------------
INSERT INTO `role_menu` VALUES ('1', '1', '1', '2', '2021-01-29 15:03:08', '2', '2021-01-29 15:03:08', '0');
INSERT INTO `role_menu` VALUES ('2', '1', '2', '2', '2021-01-29 15:03:08', '2', '2021-01-29 15:03:08', '0');
INSERT INTO `role_menu` VALUES ('3', '1', '3', '2', '2021-01-29 15:03:08', '2', '2021-01-29 15:03:08', '0');
INSERT INTO `role_menu` VALUES ('4', '1', '4', '2', '2021-01-29 15:03:08', '2', '2021-01-29 15:03:08', '0');
INSERT INTO `role_menu` VALUES ('5', '2', '1', '2', '2021-01-29 15:03:08', '2', '2021-01-29 15:03:08', '0');
INSERT INTO `role_menu` VALUES ('6', '2', '2', '2', '2021-01-29 15:03:08', '2', '2021-01-29 15:03:08', '0');
INSERT INTO `role_menu` VALUES ('7', '2', '6', '2', '2021-01-29 15:03:08', '2', '2021-01-29 15:03:08', '0');
INSERT INTO `role_menu` VALUES ('8', '3', '5', '2', '2021-01-29 15:03:08', '2', '2021-01-29 15:03:08', '0');
-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_name` varchar(20) NOT NULL DEFAULT '' COMMENT '用户名称',
`password` varchar(300) NOT NULL COMMENT '用户密码',
`mobile_phone` char(11) NOT NULL DEFAULT '' COMMENT '手机号',
`state` tinyint(4) NOT NULL COMMENT '用户状态1.启用2.禁用',
`open_id` varchar(50) NOT NULL DEFAULT '' COMMENT '微信openid\n',
`expire_time` datetime DEFAULT NULL COMMENT '过期时间',
`create_by` bigint(20) NOT NULL COMMENT '创建人id',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`last_modify_by` bigint(20) NOT NULL DEFAULT '0' COMMENT '上次修改人id',
`last_modify_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '上次修改时间',
`logical_deleted` tinyint(4) NOT NULL DEFAULT '1' COMMENT '逻辑删除1.正常2.已删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'admin', '$2a$10$sIj/zvXEJiuXIdYQuyNzEuaJsvRFmVTmsBdOX3NA//acFc7KmY3Yu', '11111111112', '1', '', '2030-01-01 00:00:00', '1', '2021-01-29 15:03:08', '1', '2021-01-29 15:03:08', '0');
INSERT INTO `user` VALUES ('2', 'cindy', '$2a$10$oid8x9NsqRcmr8GN54bDhuVI.qwbY2zsaKxYYrZiwqGH6tImpCtjy', '11111111111', '1', '', '2030-01-01 00:00:00', '1', '2021-01-29 15:03:08', '1', '2021-01-29 15:03:08', '0');
INSERT INTO `user` VALUES ('3', 'alice', '$2a$10$H7FKVYN0394QlPpMMISCBu2Z/3wm7C01gnWCn6hpl5LR.ksYEuyeO', '11111111111', '1', '', '2030-01-01 00:00:00', '1', '2021-01-29 15:03:08', '1', '2021-01-29 15:03:08', '0');
-- ----------------------------
-- Table structure for `user_role`
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`auth_user_id` bigint(20) unsigned NOT NULL COMMENT '员工id',
`role_id` bigint(20) unsigned NOT NULL COMMENT '角色id',
`create_by` bigint(20) NOT NULL COMMENT '创建人id',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`last_modify_by` bigint(20) DEFAULT NULL COMMENT '上次修改人id',
`last_modify_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '上次修改时间',
`logical_deleted` tinyint(4) NOT NULL DEFAULT '1' COMMENT '逻辑删除1.正常2.已删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT INTO `user_role` VALUES ('1', '1', '1', '2', '2021-01-29 15:03:08', '2', '2021-01-29 15:03:08', '0');
INSERT INTO `user_role` VALUES ('2', '1', '2', '1', '2021-01-29 15:03:08', '1', '2021-01-29 15:03:08', '0');
INSERT INTO `user_role` VALUES ('3', '1', '3', '1', '2021-01-29 15:03:08', '1', '2021-01-29 15:03:08', '0');
INSERT INTO `user_role` VALUES ('4', '2', '1', '2', '2021-01-29 15:03:08', '2', '2021-01-29 15:03:08', '0');
INSERT INTO `user_role` VALUES ('5', '2', '2', '1', '2021-01-29 15:03:08', '1', '2021-01-29 15:03:08', '0');
INSERT INTO `user_role` VALUES ('6', '3', '1', '1', '2021-01-29 15:03:08', '1', '2021-01-29 15:03:08', '0');
5、获得token,使用postman请求http://localhost:9090/oauth/token,
Authorization选项卡里type选择Basic Auth,username为client,password为admin
Body选项卡里设置,选中x-www-form-urlencoded,输入四个键值对:
grant_type:password
username:cindy
password:456
scope:web
返回结果:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MTY5NzY3MjIsInVzZXJfbmFtZSI6ImNpbmR5IiwiYXV0aG9yaXRpZXMiOlsiMSIsIjIiLCIzIiwiNCIsIjYiXSwianRpIjoiZjBmYzM3ZGYtMzA5Ni00YjBmLWFjNDAtZTAyYWU5YzVkOGRmIiwiY2xpZW50X2lkIjoiY2xpZW50Iiwic2NvcGUiOlsid2ViIl19.c-RpDGlbWe8etnDa915zlDwu7dW0hwGKN1SHUVvWX-E",
"token_type": "bearer",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJjaW5keSIsInNjb3BlIjpbIndlYiJdLCJhdGkiOiJmMGZjMzdkZi0zMDk2LTRiMGYtYWM0MC1lMDJhZTljNWQ4ZGYiLCJleHAiOjE2MTk1MjU1MjIsImF1dGhvcml0aWVzIjpbIjEiLCIyIiwiMyIsIjQiLCI2Il0sImp0aSI6IjA5YTcwNWQxLWViNmItNGM4Mi1hZTBlLWM1MDU1NjI5MDIzOSIsImNsaWVudF9pZCI6ImNsaWVudCJ9.sGbW--SPTztAsqOJ49HAOBRycU_Bk1qtGlcW21IBh6o",
"expires_in": 43199,
"scope": "web",
"jti": "f0fc37df-3096-4b0f-ac40-e02ae9c5d8df"
}
access_token:
token_type:
refresh_token:
expires_in:
scope:
jti: