Spring:将User设置为“all”控制器和控制器函数(而不是Principal)中的参数

时间:2017-11-24 00:34:39

标签: java spring spring-security principal

在一个简单的Web应用程序中,我可以使用过滤器检索用户(来自会话属性)并将其设置为所有servlet的参数:

内部过滤器:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    checkUser((HttpServletRequest) request);
    chain.doFilter(request, response);
}

private void checkUser(HttpServletRequest request) {
    HttpSession session = request.getSession(false);
    if (session != null) {
        request.setAttribute("user", session.getAttribute("user"));
    }
}

然后我可以在我的JSP文件(<c:if test="${not empty user}"> blablabla)中使用它:

${user.getDisplayName}

在Spring应用程序中,我必须在每个Controller函数中注入principal。即使在这种情况下,Principal也不是User,因此我每次都需要使用UserService:

@Controller
@RequestMapping("/")
public class IndexController {

    private final UserService userService;

    @Autowired
    IndexController(UserService userService) {
        this.userService = userService;
    }

    private static final String VIEW = "index";

    @RequestMapping(method = RequestMethod.GET)
    ModelAndView index(Principal principal) {
        User user = null;
        if (principal != null) {
            user = userService.findByUsername(principal.getName());
        }
        return new ModelAndView(VIEW, "user", user);
    }
}

我需要用户(实体类)对象,因为它具有我使用的不同功能。例如。我用于导航栏的getDisplayName()(在每个页面上):

用户类:

public String getDisplayName() {
    if (firstname == null && lastname == null) {
        return username;
    }
    if (firstname != null && lastname != null) {
        return String.format("%s %s", firstname, lastname);
    }
    if (firstname != null) {
        return firstname;
    }
    return lastname;
}

我无法使用安全标记库函数在Spring Framework中使用此特定用户函数(getDisplayName):

<security:authentication property="name"/> <%-- So, this is not what I am looking for --%>

好吧,我甚至尝试制作一个自定义拦截器并注册它(我不想做什么,因为我每次都要从数据库中读取我的用户)。但是我遇到了在拦截器内自动装配UserService的问题。

解决此问题的最佳方法是什么?是否有可能在成功登录后从数据库中找到User(findByUsername),然后将其放入会话中,然后制作某种拦截器,它可以执行与之前使用过滤器相同的操作,或者每次从数据库中检索用户页面,但避免这种狡猾的重复代码?

2 个答案:

答案 0 :(得分:2)

您可以提供像

这样的登录成功处理程序
http.formLogin().successHandler(new AuthenticationSuccessHandler() {

            @Override
            public void onAuthenticationSuccess(HttpServletRequest arg0,
                    HttpServletResponse arg1, Authentication arg2) throws IOException,
                    ServletException {
                // here you can put your logic to save User object into session then forward/redirect to where ever you want

            }
        })

或者您可以将登录成功转发到某个终点,例如

http.formLogin().successForwardUrl("/loginsuccess")

并提供像

这样的endpont实现
@RequestMapping({ "/loginsuccess" })
    public ResponseEntity<?> loginSuccess(Principal user) {

        // here you can put your logic to save User object into session then forward/redirect to where ever you want

        return "";
    }

选择您认为更方便的方式。

答案 1 :(得分:0)

<强>解决:

我制作了一个自定义拦截器,向其中注入了自动装配的用户服务,并注册了该自定义拦截器。它有效!

public class MyWebConfig extends WebMvcConfigurerAdapter {
    @Bean
    public UsernameInjectionInterceptor usernameInjectionInterceptor() {
        return new UsernameInjectionInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(usernameInjectionInterceptor());
    }
}
public class UsernameInjectionInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private UserService userService;

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler, ModelAndView modelAndView) throws Exception {
        Principal principal = request.getUserPrincipal();
        if (principal != null) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                String displayName = (String) session.getAttribute("displayName");
                if (displayName == null) {
                    User user = userService.findByUsername(principal.getName());
                    if (user != null) {
                        displayName = user.getDisplayName();
                        session.setAttribute("displayName", displayName);
                    }
                }
                modelAndView.addObject("displayName", displayName);
            }
        }
    }
}