Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring引导安全性-如何在成功身份验证但未成功授权后返回HTTP 403?_Java_Spring_Spring Security - Fatal编程技术网

Java Spring引导安全性-如何在成功身份验证但未成功授权后返回HTTP 403?

Java Spring引导安全性-如何在成功身份验证但未成功授权后返回HTTP 403?,java,spring,spring-security,Java,Spring,Spring Security,我有一个SpringBoot应用程序,它也使用SpringSecurity。我想检查用户是否有权登录应用程序,但必须在身份验证之后。关键是,登录时用户选择他/她必须连接的项目。用户可以连接到一个项目,但不能连接到另一个项目。但是,若用户将输入无效凭据,则必须首先显示有关无效凭据的消息,即使用户无权登录到所选项目。因此,必须在身份验证之后检查项目的权限 这是我的SecurityConfig类: package org.aze.accountingprogram.config; import or

我有一个SpringBoot应用程序,它也使用SpringSecurity。我想检查用户是否有权登录应用程序,但必须在身份验证之后。关键是,登录时用户选择他/她必须连接的项目。用户可以连接到一个项目,但不能连接到另一个项目。但是,若用户将输入无效凭据,则必须首先显示有关无效凭据的消息,即使用户无权登录到所选项目。因此,必须在身份验证之后检查项目的权限

这是我的SecurityConfig类:

package org.aze.accountingprogram.config;

import org.aze.accountingprogram.models.CurrentUser;
import org.aze.accountingprogram.models.PermissionAliasConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.Authentication;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests().antMatchers("/lib/**").permitAll().anyRequest().fullyAuthenticated()
                .and()
                .formLogin().successHandler(successHandler()).loginPage("/login").permitAll()
                .and().exceptionHandling().accessDeniedHandler(accessDeniedHandler())
                .and()
                .logout().logoutUrl("/logout").logoutSuccessUrl("/login").permitAll();

        http.csrf().disable();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(new Md5PasswordEncoder());
    }

    private AccessDeniedHandler accessDeniedHandler() {
        return (request, response, e) -> {
            logger.debug("Returning HTTP 403 FORBIDDEN with message: \"{}\"", e.getMessage());
            response.sendError(HttpStatus.FORBIDDEN.value(), e.getMessage());
        };
    }

    private AuthenticationSuccessHandler successHandler() {
        return new AuthenticationSuccessHandler() {
            @Override
            public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                CurrentUser user = (CurrentUser) authentication.getPrincipal();
                if (!user.hasAccessRight(PermissionAliasConstants.LOGIN)) {
                    throw new AccessDeniedException(String.format("User \"%s\" is not authorized to login \"%s\" project", user.getUsername(), user.getProject().getName()));
                }
            }
        };
    }

}
UserDetailsService的实现:

package org.aze.accountingprogram.serviceimpl;

import org.aze.accountingprogram.common.Constants;
import org.aze.accountingprogram.exceptions.DataNotFoundException;
import org.aze.accountingprogram.models.AccessRightsPermission;
import org.aze.accountingprogram.models.CurrentUser;
import org.aze.accountingprogram.models.Project;
import org.aze.accountingprogram.models.User;
import org.aze.accountingprogram.service.AccessRightsService;
import org.aze.accountingprogram.service.ProjectService;
import org.aze.accountingprogram.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserService userService;

    @Autowired
    private ProjectService projectService;

    @Autowired
    private AccessRightsService accessRightsService;

    @Autowired
    private HttpServletRequest request;

    private static final Logger logger = LoggerFactory.getLogger(UserDetailsServiceImpl.class);

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user;
        Project project;
        final String projectId = request.getParameter(Constants.SESSION_PROJECT_ID);
        logger.debug("Username: {}, projectId: {}", username, projectId);

        try {
            user = userService.getUserByUsername(username);
        } catch (DataNotFoundException e) {
            throw new UsernameNotFoundException(e.getMessage(), e);
        }

        // Value of projectId is from combo box which is filled from table of projects
        // That is why there is no probability that the project will not be found
        project = projectService.getProjectById(Integer.valueOf(projectId));

        // User can have different rights for different projects
        List<AccessRightsPermission> accessRights = accessRightsService.getAccessRightsByProject(user.getId(), project.getId());
        Set<GrantedAuthority> authorities = new HashSet<>(accessRights.size());
        authorities.addAll(accessRights.stream().map(right -> new SimpleGrantedAuthority(right.getAlias())).collect(Collectors.toList()));

        final CurrentUser currentUser = new CurrentUser(user, project, authorities);

        // If to check LOGIN access right to project here, and user entered right credentials
        // then user will see message about invalid credentials.
        // .and().exceptionHandling().accessDeniedHandler(accessDeniedHandler()) at SecurityConfig is not working in this case
//        if (!currentUser.hasAccessRight(PermissionAliasConstants.LOGIN)) {
//            throw new AccessDeniedException(String.format("User \"%s\" is not authorized to login \"%s\" project", user.getUsername(), project.getName()));
//        }

        logger.info("Logged in user: {}", currentUser);
        return currentUser;
    }
}
package org.aze.accountingprogram.serviceinpl;
导入org.aze.accountingprogram.common.Constants;
导入org.aze.accountingprogram.exceptions.DataNotFoundException;
导入org.aze.accountingprogram.models.AccessRightsPermission;
导入org.aze.accountingprogram.models.CurrentUser;
导入org.aze.accountingprogram.models.Project;
导入org.aze.accountingprogram.models.User;
导入org.aze.accountingprogram.service.AccessRightsService;
导入org.aze.accountingprogram.service.ProjectService;
导入org.aze.accountingprogram.service.UserService;
导入org.slf4j.Logger;
导入org.slf4j.LoggerFactory;
导入org.springframework.beans.factory.annotation.Autowired;
导入org.springframework.security.core.GrantedAuthority;
导入org.springframework.security.core.authority.SimpleGrantedAuthority;
导入org.springframework.security.core.userdetails.userdetails;
导入org.springframework.security.core.userdetails.userdetails服务;
导入org.springframework.security.core.userdetails.UsernameNotFoundException;
导入org.springframework.stereotype.Service;
导入javax.servlet.http.HttpServletRequest;
导入java.util.HashSet;
导入java.util.List;
导入java.util.Set;
导入java.util.stream.collector;
@服务
公共类UserDetailsServiceImpl实现UserDetailsService{
@自动连线
私人用户服务;
@自动连线
私人项目服务项目服务;
@自动连线
私有访问权限服务访问权限服务;
@自动连线
私有HttpServletRequest;
私有静态最终记录器Logger=LoggerFactory.getLogger(UserDetailsServiceImpl.class);
@凌驾
public UserDetails loadUserByUsername(字符串用户名)引发UsernameNotFoundException{
用户;
项目;
最后一个字符串projectId=request.getParameter(Constants.SESSION\u PROJECT\u ID);
debug(“用户名:{},projectId:{}”,用户名,projectId);
试一试{
user=userService.getUserByUsername(用户名);
}捕获(DataNotFounde异常){
抛出新的UsernameNotFoundException(e.getMessage(),e);
}
//projectId的值来自组合框,组合框由项目表填充
//这就是为什么不可能找到该项目的原因
project=projectService.getProjectById(Integer.valueOf(projectId));
//用户可以对不同的项目拥有不同的权限
List accessRights=accessRightsService.getAccessRightsByProject(user.getId(),project.getId());
Set authorities=newhashset(accessRights.size());
authorities.addAll(accessRights.stream().map(右->新建SimpleGrantedAuthority(右.getAlias()).collect(Collectors.toList());
最终CurrentUser CurrentUser=新的CurrentUser(用户、项目、权限);
//如果要在此处检查项目的登录访问权限,以及用户输入的正确凭据
//然后用户将看到关于无效凭据的消息。
//.and().exceptionHandling().SecurityConfig上的accessDeniedHandler(accessDeniedHandler())在这种情况下不起作用
//如果(!currentUser.hasAccessRight(PermissionAliasConstants.LOGIN)){
//抛出新的AccessDeniedException(String.format(“用户\%s\”无权登录\%s\“项目”、User.getUsername()、project.getName());
//        }
info(“登录用户:{}”,currentUser);
返回当前用户;
}
}
和登录控制器

package org.aze.accountingprogram.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import java.util.Optional;

@Controller
public class LoginController {

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public ModelAndView getLoginPage(@RequestParam Optional<String> error) {
        return new ModelAndView("login", "error", error);
    }

}
package org.aze.accountingprogram.controllers;
导入org.springframework.stereotype.Controller;
导入org.springframework.web.bind.annotation.RequestMapping;
导入org.springframework.web.bind.annotation.RequestMethod;
导入org.springframework.web.bind.annotation.RequestParam;
导入org.springframework.web.servlet.ModelAndView;
导入java.util.Optional;
@控制器
公共类登录控制器{
@RequestMapping(value=“/login”,method=RequestMethod.GET)
公共模型和视图getLoginPage(@RequestParam可选错误){
返回新的ModelAndView(“登录”,“错误”,错误);
}
}
successHandler()
工作,如果用户没有登录项目的访问权限,应用程序将抛出
AccessDeniedException
。但是
accessDeniedHandler()
不工作,也不发送HTTP 403。相反,我接收HTTP 500


如何返回HTTP 403响应和异常消息(例如,“用户”未被授权登录“AZB”项目),并在
LoginController
中处理它(使用
@ResponseStatus(HttpStatus.probled)
@ExceptionHandler
)?

不确定这是否是您正在寻找的,但是您可以在控制器的login POST方法中插入
HttpServletResponse

因此,如果您的服务通知您授权不正常,您可以这样做

答复:setStatus(403)

//更新:

自从

public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException 
方法是
org.springframework.security.core.userdetails.userdetails服务
接口的实现,实际上您不能像您一样注入
HttpServletResponse
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException 
@ControllerAdvice
public class ExceptionHandlingController {

   @ExceptionHandler({CustomYourException.class})
   public ModelAndView handleCustomExceptionError(HttpServletRequest request, HttpServletResponse response, CustomYourException cyee) {
       // this method will be triggered upon CustomYourException only
       // you can manipulate the response code here, 
       // return a custom view, use a special logger
       // or do whatever else you want here :)
   }
}