目录
一、项目实现
增加数据库表:
sql:
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(200) COLLATE utf8mb4_general_ci NOT NULL,
`description` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL,
`url` varchar(200) COLLATE utf8mb4_general_ci NOT NULL,
`pid` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- ----------------------------
-- Records of sys_permission
-- ----------------------------
INSERT INTO `sys_permission` VALUES ('1', 'ROLE_HOME', 'home', '/', null);
INSERT INTO `sys_permission` VALUES ('2', 'ROLE_ADMIN', 'ABel', '/admin', null);
INSERT INTO `sys_permission` VALUES ('4', 'ROLE_USER', 'user', '/getUser', null);
-- ----------------------------
-- Table structure for sys_permission_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission_role`;
CREATE TABLE `sys_permission_role` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`role_id` bigint(20) unsigned NOT NULL,
`permission_id` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- ----------------------------
-- Records of sys_permission_role
-- ----------------------------
INSERT INTO `sys_permission_role` VALUES ('1', '1', '1');
INSERT INTO `sys_permission_role` VALUES ('2', '1', '2');
INSERT INTO `sys_permission_role` VALUES ('3', '2', '1');
INSERT INTO `sys_permission_role` VALUES ('4', '1', '4');
-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(200) COLLATE utf8mb4_general_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES ('1', 'ROLE_ADMIN');
INSERT INTO `sys_role` VALUES ('2', 'ROLE_USER');
-- ----------------------------
-- Table structure for sys_role_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_user`;
CREATE TABLE `sys_role_user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`sys_user_id` bigint(20) unsigned NOT NULL,
`sys_role_id` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- ----------------------------
-- Records of sys_role_user
-- ----------------------------
INSERT INTO `sys_role_user` VALUES ('1', '1', '1');
INSERT INTO `sys_role_user` VALUES ('2', '2', '2');
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(200) COLLATE utf8mb4_general_ci NOT NULL,
`password` varchar(200) COLLATE utf8mb4_general_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('1', 'admin', '202cb962ac59075b964b07152d234b70');
INSERT INTO `sys_user` VALUES ('2', 'abel', 'abel');
public class Permission {
private int id;
//权限名称
private String name;
//权限描述
private String descritpion;
//授权链接
private String url;
..
}
public class SecurityUser implements UserDetails {
private static final long serialVersionUID=1L;
private Long id;
private String username;
private String password;
private List<GrantedAuthority> anthorities;
...
}
mapper:
public interface PermissionMapper {
@Select("select * from sys_permission")
public List<Permission> findAll();
@Select("select p.* " +
"from Sys_User u " +
"LEFT JOIN sys_role_user sru on u.id= sru.Sys_User_id " +
"LEFT JOIN Sys_Role r on sru.Sys_Role_id=r.id " +
"LEFT JOIN Sys_permission_role spr on spr.role_id=r.id " +
"LEFT JOIN Sys_permission p on p.id =spr.permission_id " +
"where u.id=#{userId}")
public List<Permission> findByAdminUserId(Long userId);
}
public interface SecurityUserMapper {
//新增用户
@Insert("insert into sys_user(username,password) value(#{username},#{password})")
@Options(useGeneratedKeys=true,keyColumn="id",keyProperty="id")
public void insert(SecurityUser SecurityUser);
//查找所有用户
@Select("select * from sys_user")
public List<SecurityUser> getAll();
//根据id查找用户
@Select("select * from sys_user where id=#{id}")
public SecurityUser getById(int id);
@Select("select * from sys_user where username=#{username}")
public SecurityUser getByName(String username);
//根据id删除用户
@Delete("delete from sys_user where id=#{id}")
public boolean deleteById(int id);
}
加入自定义许可逻辑
MySecurityMetadataSource类,继承于FilterInvocationSecurityMetadataSource; 获取路径所需角色
public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
private Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
private PermissionMapper permissionMapper;
private HashMap<String, Collection<ConfigAttribute>> map =null;
@PostConstruct
public void init() {
map = new HashMap<>();
Collection<ConfigAttribute> array;
ConfigAttribute cfg;
List<Permission> permissions = permissionMapper.findAll();
for(Permission permission : permissions) {
array = new ArrayList<>();
cfg = new SecurityConfig(permission.getName());
array.add(cfg);
map.put(permission.getUrl(), array);
}
}
@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
HttpServletRequest request = ((FilterInvocation) object).getRequest();
AntPathRequestMatcher matcher;
for (String resUrl : map.keySet()) {
log.info("MySecurityMetadataSource resUrl:{} request:{}", resUrl, request.getRequestURI());
matcher = new AntPathRequestMatcher(resUrl);
if (matcher.matches(request)) {
// ConfigAttribute configAttribute = new MyConfigAttribute(request,new MyGrantedAuthority(jurisdiction.getMethod(),jurisdiction.getUrl()));
// allConfigAttribute.add(configAttribute);
// return allConfigAttribute;
return map.get(resUrl);
}
}
return null;
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> clazz) {
// return FilterInvocation.class.isAssignableFrom(clazz);
return true;
}
}
MyAccessDecisionManager类,继承于AccessDecisionManager, 用户角色与路径角色是否匹配。
public class MyAccessDecisionManager implements AccessDecisionManager {
private Logger log = LoggerFactory.getLogger(this.getClass());
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
log.info("MyAccessDecisionManager join");
if(configAttributes == null || configAttributes.size()==0) {
return;
}
// if(!authentication.isAuthenticated()) {
// throw new InsufficientAuthenticationException("未登录");
// }
// Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
// for(ConfigAttribute attribute : collection){
// MyConfigAttribute urlConfigAttribute = (MyConfigAttribute)attribute;
// for(GrantedAuthority authority: authorities){
// MyGrantedAuthority myGrantedAuthority = (MyGrantedAuthority)authority;
// if(urlConfigAttribute.getMyGrantedAuthority().equals(myGrantedAuthority))
// return;
// }
// }
String needRole;
for (ConfigAttribute c : configAttributes) {
needRole = c.getAttribute();
log.info("MyAccessDecisionManager needRole:{}", needRole);
for(GrantedAuthority ga : authentication.getAuthorities()) {//authentication 为在注释1 中循环添加到 GrantedAuthority 对象中的权限信息集合
log.info("MyAccessDecisionManager ga:{}", ga.getAuthority());
if(needRole.trim().equals(ga.getAuthority())) {
return;
}
}
}
throw new AccessDeniedException("无权限");
}
@Override
public boolean supports(ConfigAttribute configAttribute) {
return true;
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
MyFilterSecurityInterceptor类,过滤器,设置后角色权限逻辑通过过滤器启用
@Component
public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private MySecurityMetadataSource mySecurityMetadataSource;
@Autowired
private MyAccessDecisionManager myAccessDecisionManager;
@PostConstruct
public void setMyAccessDecisionManager() {
super.setAccessDecisionManager(myAccessDecisionManager);
}
@Override
public Class<?> getSecureObjectClass() {
return FilterInvocation.class;
}
@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return mySecurityMetadataSource;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}
public void invoke(FilterInvocation fi) throws IOException, ServletException {
logger.info("MyFilterSecurityInterceptor {}", fi.getRequest().getRequestURI());
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} finally {
super.afterInvocation(token, null);
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
在SecurityConfig中,配置过滤器,启用逻辑
http.addFilterBefore(urlFilterSecurityInterceptor , FilterSecurityInterceptor.class);
二、测试
- 启动
- 访问路径 http://localhost:8001/getUser,跳转登陆界面
- 输入账户密码 admin/123
- 显示getUser接口信息
用户注册登陆时逻辑
-
SecurityUserService 获取用户名密码以及用户权限
-
MyPasswordEncoder 加密并匹配密码
-
MyFilterSecurityInterceptor 过滤器,设置后角色权限逻辑通过过滤器启用
-
MySecurityMetadataSource 获取路径所需角色
-
MyAccessDecisionManager 用户角色与路径角色是否匹配