如题,在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; } }
应该是你的springSecurity被加载在springIOC的子容器,所以注解放在controller上生效,如果把springSecuirty被加载在springIOC父容器中,注解放在service上才会生效