数据库设计
2.自定义CustomFilterInvocationSecurityMetadaSource(获取角色信息)
@Component
public class CustomFilterInvocationSecurityMetadaSource implements FilterInvocationSecurityMetadataSource {
AntPathMatcher antPathMatcher=new AntPathMatcher();//实现ant风格的URL匹配
@Resource
private MenuMapper menuMapper;
@Override
public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
String requestUrl = ((FilterInvocation) o).getRequestUrl();//当前请求路径
List<Menu> allMenus = menuMapper.getAllMenus();
//遍历资源信息
for (Menu menu:
allMenus) {
//判断当前请求的URL在资源表中是否存在相应的模式,不存在则假设请求登录后即可访问
if(antPathMatcher.match(menu.getPattern(),requestUrl)){
List<Role> roles=menu.getRoles();
String[] roleArr=new String[roles.size()];
for (int i = 0; i <roleArr.length ; i++) {
roleArr[i]=roles.get(i).getName();
}
return SecurityConfig.createList(roleArr);
}
}
return SecurityConfig.createList("ROLE_LOGIN");
}
/**
* 返回所有已经定义好的权限资源,spring security启动时会检验相关配置是否正确,不需检验,则返回null
* @return
*/
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
/**
* 返回对象是否支持检验
* @param aClass
* @return
*/
@Override
public boolean supports(Class<?> aClass) {
return FilterInvocation.class.isAssignableFrom(aClass);
}
}
3.自定义AccessDecisionManager(对比角色信息)
/**
*
* @param auth 当前登录用户的信息
* @param o FilterInvocation对象,可获取当前请求对象
* @param ca FilterInvocationSecurityMetadataSource中的getAttribute的返回值
* Collection<ConfigAttribute> 当前请求URL所需的角色
* @throws AccessDeniedException
* @throws InsufficientAuthenticationException
*/
@Override
public void decide(Authentication auth, Object o, Collection<ConfigAttribute> ca) throws AccessDeniedException, InsufficientAuthenticationException {
/**
* 判断当前登录的用户
* 是否具有当前请求所需要的角色信息
* 不具备,抛出AccessDeniedException异常,否则不需任何事即可
*/
Collection<? extends GrantedAuthority> auths = auth.getAuthorities();
for (ConfigAttribute configAttribute:
ca) {
if("ROLE_LOGIN".equals(configAttribute.getAttribute())
&& auth instanceof UsernamePasswordAuthenticationToken){
return;
}
for (GrantedAuthority authority:auths){
if(configAttribute.getAttribute().equals(authority.getAuthority())){
return;
}
}
}
throw new AccessDeniedException("权限不足");
}
@Override
public boolean supports(ConfigAttribute configAttribute) {
return true;
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
4.mapper+xml
@Mapper
public interface MenuMapper {
List<Menu> getAllMenus();
}
<?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.example.demo.mapper.MenuMapper">
<resultMap id="BaseResultMap" type="com.example.demo.pojo.Menu">
<id property="id" column="id"/>
<result property="pattern" column="pattern"/>
<collection property="roles" ofType="com.example.demo.pojo.Role">
<id property="id" column="rid"/>
<result property="name" column="rname"/>
<result property="nameZh" column="rnameZh"/>
</collection>
</resultMap>
<select id="getAllMenus" resultMap="BaseResultMap">
SELECT m.*,
r.id AS rid,
r.name AS rname,
r.nameZh AS rnameZh
FROM menu m
LEFT JOIN menu_role mr ON m.id=mr.mid
LEFT JOIN role r ON mr.`rid`=r.id
</select>
</mapper>
5.配置类
@Configuration
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter{
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception{
http.authorizeRequests()
.withObjectPostProcessor(new ObjectPostProcessor() {
@Override
public O postProcess(O o) {
o.setSecurityMetadataSource(cfisms());
o.setAccessDecisionManager(cadm());
return o;
}
})
.and()
.formLogin()
.loginProcessingUrl("/login").permitAll()
.and()
.csrf().disable();
}
@Bean
CustomFilterInvocationSecurityMetadaSource cfisms(){
return new CustomFilterInvocationSecurityMetadaSource();
}
@Bean
CustomAccessDesisionManager cadm(){
return new CustomAccessDesisionManager();
}
}