首页 新闻 会员 周边 捐助

springboot整合security 权限注解@PreAuthorize在controller中方法上有效,在service接口层上无效

0
悬赏园豆:40 [待解决问题]

如题,在controller中方法上使用@PreAuthorize("hasAnyRole('USER')") 可以正常处理权限,但是在service中方法上就无效

问题补充:

用户登录AuthenticationProvider:

package com.example.demo6role2.config;

import com.example.demo6role2.service.UserDetailServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * 自定义登录校验器
 */
@Component
public class MyAuthProvider implements AuthenticationProvider {
    @Autowired
    private UserDetailServiceImpl userDetailServiceImpl;
    private static UserDetailServiceImpl userDetailService;

    @PostConstruct
    public void setService() {
        userDetailService = userDetailServiceImpl;
    }

    /**
     * 进行登录用户名密码校验
     *
     * @param authentication
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        // 获取用户输入的用户名和密码
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();
        // 获取封装用户信息的对象
        UserDetails userDetails = userDetailService.loadUserByUsername(username);
        // 进行密码的比对
//        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        SecurityPasswordEncoder passwordEncoder = new SecurityPasswordEncoder();
        boolean flag = passwordEncoder.matches(password, userDetails.getPassword());
        // 校验通过
        if (flag) {
            // 将权限信息也封装进去
            return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
        }

        // 验证失败返回 null
        return null;

    }

    /**
     * 开启自定义支持
     *
     * @param aClass
     * @return
     */
    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }


}

 

userDetail接口:

package com.example.demo6role2.service;

import com.example.demo6role2.entity.Role;
import com.example.demo6role2.mapper.RoleMapper;
import com.example.demo6role2.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
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.Service;

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

@Service
public class UserDetailServiceImpl implements UserDetailsService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RoleMapper roleMapper;

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        com.example.demo6role2.entity.User user = userMapper.selectUserByName(userName);
        if (user == null) {
            throw new RuntimeException("user is null");
        }

        // 添加角色
        List<Role> roles = roleMapper.selectRoleByUserId(user.getId());
        List<GrantedAuthority> authorities = new ArrayList<>();
        for (int i = 0; i < roles.size(); i++) {
            authorities.add(new SimpleGrantedAuthority(roles.get(i).getRoleName()));
        }

        User myUser = new User(user.getUsername(), user.getPassword(), authorities);
        return myUser;
    }
}

 

security配置:

package com.example.demo6role2.config;

import com.example.demo6role2.handler.MyAuthFailureHandler;
import com.example.demo6role2.handler.MyAuthSuccessHandler;
import com.example.demo6role2.handler.MyLogoutSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyAuthSuccessHandler myAuthSuccessHandler;
    @Autowired
    private MyAuthFailureHandler myAuthFailureHandler;
    @Autowired
    private MyLogoutSuccessHandler myLogoutSuccessHandler;


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        System.out.println("auth configure");
        //启用自定义登录处理器,动态从数据库比对用户名密码并返回UserDetails给Security
        auth.authenticationProvider(new MyAuthProvider());
    }

    /**
     * security 登录登出配置
     * 【注意】登录登出url应是post方式
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        System.out.println("http configure");
        http.authorizeRequests()
                .antMatchers("/openToLogin", "/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                //配置自定义登录页面
                .loginPage("/openToLogin")
                //配置自定义的登录表单action
                .loginProcessingUrl("/login")
                //配置自定义的登录表单中的用户名与密码
                .usernameParameter("uname")
                .passwordParameter("pwd")
                //登录成功/失败处理器
//                .successHandler(myAuthSuccessHandler)
//                .failureHandler(myAuthFailureHandler)
                //登录成功/失败跳转url, 可以用于返回提示页面或提示信息等
                .defaultSuccessUrl("/index")
                .and()
                //配置登出
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/openToLogin")
                //登出成功处理器
                .logoutSuccessHandler(myLogoutSuccessHandler)
                .and()
                .httpBasic();
    }

    @Override
    public UserDetailsService userDetailsServiceBean() throws Exception {
        return super.userDetailsServiceBean();
    }

}

 

权限配置:

package com.example.demo6role2.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;

/**
 * 开启权限控制
 */
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class PermissionConfig extends GlobalMethodSecurityConfiguration {
    @Autowired
    private MyPermissionEvaluator myPermissionEvaluator;

    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
        expressionHandler.setPermissionEvaluator(myPermissionEvaluator);
        return expressionHandler;
        //return super.createExpressionHandler();
    }


}

 

Evaluator(这里面是我从数据库中获取对应角色拥有哪些url,再与请求的url进行比对,而进行的权限校验,和外面的hasRole应该没有关系吧。。。。):

package com.example.demo6role2.config;

import com.example.demo6role2.entity.Url;
import com.example.demo6role2.service.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

/**
 * 自定义权限过滤器
 */
@Configuration
public class MyPermissionEvaluator implements PermissionEvaluator {
    @Autowired
    private RoleService roleService;

    /**
     * 通过请求过来的url和数据库中的角色对应url来对应校验权限
     *
     * @param authentication
     * @param targetUrl
     * @param targetPermission
     * @return
     */
    @Override
    public boolean hasPermission(Authentication authentication, Object targetUrl, Object targetPermission) {
        System.out.println("第一个hasPermission : targetUrl : " + targetUrl);
        System.out.println("第一个hasPermission : targetPermission : " + targetPermission);
        // 获得loadUserByUsername()方法的结果
        User user = (User) authentication.getPrincipal();
        // 获得loadUserByUsername()中注入的角色
        Collection<GrantedAuthority> authorities = user.getAuthorities();

        // 遍历用户所有角色
        for (GrantedAuthority authority : authorities) {
            String roleName = authority.getAuthority();
            Integer roleId = roleService.getRoleByName(roleName).getId();

            // 得到角色所有的url权限
            List<Url> urls = roleService.listUrlsByRole(roleId);

            // 遍历permissionList
            for (Url url : urls) {
                // 如果访问的Url和权限用户符合的话,返回true
                if (targetUrl.equals(url.getUrl())) {
                    return true;
                }
            }

        }

        return false;
    }

    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object targetPermission) {
        System.out.println("第二个hasPermission: targetId=" + targetId);
        System.out.println("第二个hasPermission: targetType=" + targetType);
        System.out.println("第二个hasPermission: targetPermission=" + targetPermission);
        return false;
    }
}

 

派小星的主页 派小星 | 初学一级 | 园豆:114
提问于:2019-08-02 14:27
< >
分享
所有回答(1)
0

应该是你的springSecurity被加载在springIOC的子容器,所以注解放在controller上生效,如果把springSecuirty被加载在springIOC父容器中,注解放在service上才会生效

h3110n3w0r1d | 园豆:202 (菜鸟二级) | 2020-11-26 18:49
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册