srpingboot2.2.2 springsecurity5.2.1 自定义权限

基本全是这篇文章的代码:http://www.javaboy.org/2019/1015/springsecurity.html

第一步 

import java.util.Collection;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import com.derek.laundry.entity.SeMenu;
import com.derek.laundry.entity.SeRole;
import com.derek.laundry.service.SeMenuService;

/**
 * 这个类的作用,主要是根据用户传来的请求地址,分析出请求需要的角色
 * 
 */
@Component
public class WebFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    @Autowired
    SeMenuService menuService;

    AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        String requestUrl = ((FilterInvocation) object).getRequestUrl();

//查询所有菜单以及对应的权限
        List<SeMenu> menus = menuService.selectAllMenu();
        for (SeMenu menu : menus) {
            if (antPathMatcher.match(menu.getUrl(), requestUrl)) {
                List<SeRole> roles = menu.getSeRole();
                String[] str = new String[roles.size()];
                for (int i = 0; i < roles.size(); i++) {
                    str[i] = roles.get(i).getRoleKey();
                }
                return SecurityConfig.createList(str);
            }
        }
        return SecurityConfig.createList("ROLE_LOGIN");
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }

}
 

第二步

 

import java.util.Collection;

import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;

/**
 * 自定义权限决策管理器
 */
@Component
public class WebUrlAccessDecisionManager implements AccessDecisionManager {

    /**
     * decide 方法是判定是否拥有权限的决策方法, 
     * 参数1:authentication 是UserService中循环添加到 GrantedAuthority对象中的权限信息集合. 
     * 参数2:object 包含客户端发起的请求的requset信息,可转换为 HttpServletRequest request =((FilterInvocation) object).getHttpRequest();
     * 参数3: configAttributes为WebFilterInvocationSecurityMetadataSource的getAttributes(Object object)这个方法返回的结果,
     * 此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。
     */
    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
            throws AccessDeniedException, InsufficientAuthenticationException {

        for (ConfigAttribute configAttribute : configAttributes) {

            String needRole = configAttribute.getAttribute();
            if ("ROLE_LOGIN".equals(needRole)) {
                if (authentication instanceof AnonymousAuthenticationToken) {
                    throw new AccessDeniedException("尚未登录,请登录!");
                } else {
                    return;
                }
            }
            Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
            for (GrantedAuthority authority : authorities) {
                if (authority.getAuthority().equals(needRole)) {
                    return;
                }
            }
        }

        throw new AccessDeniedException("权限不足,请联系管理员!");
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        // TODO Auto-generated method stub
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        // TODO Auto-generated method stub
        return true;
    }

}
第三部

 

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 

/**
 * <p>
 * 服务实现类

user roler 类就是自己的表字段,没有任何其他集成、实现接口等等
 * </p>
 *
 * @since 2020-01-19
 */
@Service
public class SeUserService implements UserDetailsService {

    @Autowired
    private SeRoleMapper seRoleMapper;

    /**
     *
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        //根据用户名查询用户
        SeUser seUser = this.baseMapper.selectOne(username);

        if (seUser == null) {
            throw new UsernameNotFoundException("用户名不存在!");
        }

//获取到当前用户所有权限
        List<SeRole> roleList = seRoleMapper.selectRoleByUserId(seUser.getUserId());

        List<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();

        if (roleList != null && !roleList.isEmpty()) {
            roleList.stream().forEach(role -> authorities.add(new SimpleGrantedAuthority(role.getRoleKey())));
        }
        return new User(seUser.getUsername(), seUser.getPassword(), authorities);
    }

}
第四步

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import com.derek.common.JSONResult;
import com.derek.laundry.service.SeUserService;
import com.fasterxml.jackson.databind.ObjectMapper;

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    SeUserService seUserService;
     
    @Autowired
    WebFilterInvocationSecurityMetadataSource webFilterInvocationSecurityMetadataSource;
    @Autowired
    WebUrlAccessDecisionManager webUrlAccessDecisionManager;

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 配置认证时用户信息获取来源以及密码校验规则
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(seUserService).passwordEncoder(new BCryptPasswordEncoder());
    }

    /**
     * 配置放行的资源
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**", "/favicon.ico", "/fonts/**", "/login.do", "/login.html", "/error");
    }

    /**
     * @Description: HttpSecurity包含了原数据(主要是url)
     *               通过withObjectPostProcessor将WebFilterInvocationSecurityMetadataSource和WebUrlAccessDecisionManager注入进来
     *               此url先被WebFilterInvocationSecurityMetadataSource处理,然后 丢给
     *               MyAccessDecisionManager处理 如果不匹配,返回 MyAccessDeniedHandler
     * 
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
         
        

        http.authorizeRequests()
//                .anyRequest().authenticated()
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O object) {
                        object.setAccessDecisionManager(webUrlAccessDecisionManager);
                        object.setSecurityMetadataSource(webFilterInvocationSecurityMetadataSource);
                        return object;
                    }
                }).and().formLogin().usernameParameter("username").passwordParameter("password")

//   /login是登录页面的请求,/doLogin是登录页面表单的请求接口地址
                .loginProcessingUrl("/doLogin").loginPage("/login").successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp,
                            Authentication authentication) throws IOException, ServletException {
                        resp.setContentType("application/json;charset=utf-8");
                        PrintWriter out = resp.getWriter();

                        String s = new ObjectMapper().writeValueAsString(JSONResult.ok("登录成功"));
                        out.write(s);
                        out.flush();
                        out.close();
                    }
                }).failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp,
                            AuthenticationException exception) throws IOException, ServletException {
                        resp.setContentType("application/json;charset=utf-8");
                        PrintWriter out = resp.getWriter();
                        String message = "登录失败!";
                        if (exception instanceof LockedException) {
                            message = "账户被锁定,请联系管理员!";
                        } else if (exception instanceof CredentialsExpiredException) {
                            message = "密码过期,请联系管理员!";
                        } else if (exception instanceof AccountExpiredException) {
                            message = "账户过期,请联系管理员!";
                        } else if (exception instanceof DisabledException) {
                            message = "账户被禁用,请联系管理员!";
                        } else if (exception instanceof BadCredentialsException) {
                            message = "用户名或者密码输入错误,请重新输入!";
                        }
                        out.write(new ObjectMapper().writeValueAsString(JSONResult.errorMsg(message)));
                        out.flush();
                        out.close();
                    }
                }).permitAll().and().logout() // 注销成功之后来到首页
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp,
                            Authentication authentication) throws IOException, ServletException {
                        resp.setContentType("application/json;charset=utf-8");
                        PrintWriter out = resp.getWriter();
                        out.write(new ObjectMapper().writeValueAsString(JSONResult.ok("注销成功!")));
                        out.flush();
                        out.close();
                    }
                }).permitAll().and().csrf().disable().exceptionHandling()
                // 没有认证时,在这里处理结果,不要重定向
                .authenticationEntryPoint(new AuthenticationEntryPoint() {
                    @Override
                    public void commence(HttpServletRequest req, HttpServletResponse resp,
                            AuthenticationException authException) throws IOException, ServletException {
                        resp.setContentType("application/json;charset=utf-8");
                        resp.setStatus(401);
                        PrintWriter out = resp.getWriter();
                        String message = "访问失败!";
                        if (authException instanceof InsufficientAuthenticationException) {
                            message = "请求失败,请联系管理员!";
                        }
                        out.write(new ObjectMapper().writeValueAsString(JSONResult.errorMsg(message)));
                        out.flush();
                        out.close();
                    }
                });

    }

}
 

完成

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值