Spring Boot-登录后返回用户对象 [英] Spring boot - return user object after log in

查看:280
本文介绍了Spring Boot-登录后返回用户对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个配置为这样的WebSecurityConfigurerAdapter的spring boot应用程序-

http.csrf().disable()
                    .exceptionHandling()
                    .authenticationEntryPoint(restAuthenticationEntryPoint)
                    .and()
                .authorizeRequests()
                    .antMatchers("/user/*", "/habbit/*").authenticated()
                    .and()
                .formLogin()
                    .loginProcessingUrl("/login")
                    .permitAll()
                    .usernameParameter("email")
                    .passwordParameter("pass")
                    .successHandler(authenticationSuccessHandler)
                    .failureHandler(new SimpleUrlAuthenticationFailureHandler())
                    .and()
                .logout()
                    .logoutUrl("/logout")
                    .invalidateHttpSession(true);

我是否可以添加类似我自己的控制器的内容,以便在成功通过身份验证后返回自定义对象,其中包含有关已身份验证用户的一些详细信息?

更新: 为了清楚起见,我使用一个有角度的应用程序作为客户端. 目前,我需要从客户端向服务器发出2个请求: 1.向/login URL发出POST请求以进行身份​​验证. 2. GET请求以检索经过身份验证的用户数据.

我的目标是让第一个请求返回给我用户信息,因此我不必发出第二个DNS请求. 当前,第一个请求仅对用户进行身份验证,在服务器上创建会话,并发回带有无数据的"200 OK"状态响应.我希望它返回有关登录用户的成功数据.

回答:

正确答案在注释中,因此我将在此处写下: 我需要从successHandler重定向到控制器,控制器又返回当前登录的用户信息(在我的情况下,控制器位于url'/user/me'中:

 @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws ServletException, IOException {
        clearAuthenticationAttributes(request);
        getRedirectStrategy().sendRedirect(request, response, "/user/me");
    }

解决方案

如果我正确地理解了您的问题,我可以建议采取另一种方法.

首先,您必须实现类,其中将包含用户信息.此类必须从org.springframework.security.core.userdetails.User:

继承

public class CustomUserDetails extends User {

    public CustomUserDetails(String username, String password,
         Collection<? extends GrantedAuthority> authorities) {            
        super(username, password, authorities);
    }

    //for example lets add some person data        
    private String firstName;
    private String lastName;

    //getters and setters
}

下一步,您已经创建了自己的接口org.springframework.security.core.userdetails.UserDetailsService的实现:

@Service
public class CustomUserDetailService implements UserDetailsService{

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException{         

        if(StringUtils.isEmpty(userName)) 
            throw new UsernameNotFoundException("User name is empty");

        //if you don't use authority based security, just add empty set
        Set<GrantedAuthority> authorities = new HashSet<>();
        CustomUserDetails userDetails = new CustomUserDetails(userName, "", authorities);            

        //here you can load user's data from DB or from 
        //any other source and do:
        //userDetails.setFirstName(firstName);
        //userDetails.setLastName(lastName);

        return userDetails;
    }

}

如您所见,此类只有一个方法,您可以在其中加载和设置自定义用户详细信息.请注意,我用@Service批注标记了该类.但是您可以在Java-config或XML上下文中注册它.

现在,要在成功通过身份验证后访问用户数据,可以使用下一种方法,当Spring将在控制器的方法中自动传递主体时:

@Controller
public class MyController{

    @RequestMapping("/mapping")
    public String myMethod(Principal principal, ModelMap model){
        CustomUserDetails userDetails = (CustomUserDetails)principal;
        model.addAttribute("firstName", userDetails.getFirstName());
        model.addAttribute("lastName", userDetails.getLastName());
    }
}

或另一种方式:

@Controller
public class MyController{

    @RequestMapping("/mapping")
    public String myMethod(ModelMap model){
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        CustomUserDetails userDetails = (CustomUserDetails)auth.getPrincipal();
        model.addAttribute("firstName", userDetails.getFirstName());
        model.addAttribute("lastName", userDetails.getLastName());
    }
}

该方法可以在Spring无法自动通过主体的其他地方使用.

要在成功通过身份验证后转到特定地址,可以使用SimpleUrlAuthenticationSuccessHandler.只需在您的配置中创建它即可:

@Bean
public SavedRequestAwareAuthenticationSuccessHandler successHandler() {
    SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
    successHandler.setTargetUrlParameter("/succeslogin");
    return successHandler;
}

并在您的配置中使用它:

http.formLogin()
    .loginProcessingUrl("/login")
    .permitAll()
    .usernameParameter("email")
    .passwordParameter("pass")
    .successHandler(successHandler())

之后,您可以创建控制器,该控制器将从指定的网址发送响应:

@Controller
@RequestMapping("/sucesslogin")
public class SuccessLoginController{

     @RequestMapping(method = RequestMethod.POST)
     public String index(ModelMap model, Principal principal){
         //here you can return view with response
     }

}

当然,您不仅可以返回视图,而且还可以返回JSON响应(使用@ResponseBody注释)或其他方式,这取决于您的前端. 希望这会有所帮助.

I have a spring boot application with WebSecurityConfigurerAdapter configured like this -

http.csrf().disable()
                    .exceptionHandling()
                    .authenticationEntryPoint(restAuthenticationEntryPoint)
                    .and()
                .authorizeRequests()
                    .antMatchers("/user/*", "/habbit/*").authenticated()
                    .and()
                .formLogin()
                    .loginProcessingUrl("/login")
                    .permitAll()
                    .usernameParameter("email")
                    .passwordParameter("pass")
                    .successHandler(authenticationSuccessHandler)
                    .failureHandler(new SimpleUrlAuthenticationFailureHandler())
                    .and()
                .logout()
                    .logoutUrl("/logout")
                    .invalidateHttpSession(true);

Can I add something like my own controller that would, after successful authentication, return back a custom object with some details about the authenticated user?

Update: To clarity, i'm using an angular application as the client. Currently I need to make 2 requests form my client to the server: 1. POST request to /login URL for authentication. 2. GET request to retrieve authenticated user data.

My aim is to have the 1st request return to me user information so I don't have to make the 2dn request. Currently the 1st request only authenticates the user, creates a session on the server and send back a '200 OK' status response with no data. I want it to return a success response with data about the logged in user.

Answered:

The correct answer is in comments so i will write it here: I needed to redirect from my successHandler to my controller which in turn returns the currently logged in user info ( in my case controller is in url '/user/me':

 @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws ServletException, IOException {
        clearAuthenticationAttributes(request);
        getRedirectStrategy().sendRedirect(request, response, "/user/me");
    }

解决方案

If I understand your problem right, I can suggest next way.

First of all you have to implement class, that will contain user information. This class must be inherited from org.springframework.security.core.userdetails.User:

public class CustomUserDetails extends User {

    public CustomUserDetails(String username, String password,
         Collection<? extends GrantedAuthority> authorities) {            
        super(username, password, authorities);
    }

    //for example lets add some person data        
    private String firstName;
    private String lastName;

    //getters and setters
}

Next step, you have create you own implementation of interface org.springframework.security.core.userdetails.UserDetailsService:

@Service
public class CustomUserDetailService implements UserDetailsService{

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException{         

        if(StringUtils.isEmpty(userName)) 
            throw new UsernameNotFoundException("User name is empty");

        //if you don't use authority based security, just add empty set
        Set<GrantedAuthority> authorities = new HashSet<>();
        CustomUserDetails userDetails = new CustomUserDetails(userName, "", authorities);            

        //here you can load user's data from DB or from 
        //any other source and do:
        //userDetails.setFirstName(firstName);
        //userDetails.setLastName(lastName);

        return userDetails;
    }

}

As you see, this class has just one method, where you can load and set custom user details. Note, that I marked this class with @Service annotation. But you can register it in your Java-config or XML context.

Now, to access your user data after successful authentication, you can use next approach, when Spring will automatically pass principal in controller's method:

@Controller
public class MyController{

    @RequestMapping("/mapping")
    public String myMethod(Principal principal, ModelMap model){
        CustomUserDetails userDetails = (CustomUserDetails)principal;
        model.addAttribute("firstName", userDetails.getFirstName());
        model.addAttribute("lastName", userDetails.getLastName());
    }
}

Or another one way:

@Controller
public class MyController{

    @RequestMapping("/mapping")
    public String myMethod(ModelMap model){
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        CustomUserDetails userDetails = (CustomUserDetails)auth.getPrincipal();
        model.addAttribute("firstName", userDetails.getFirstName());
        model.addAttribute("lastName", userDetails.getLastName());
    }
}

This method can be used in other places, where Spring does not pass principal automatically.

To go to specific address after successful authentication you can use SimpleUrlAuthenticationSuccessHandler. Just create it in your config:

@Bean
public SavedRequestAwareAuthenticationSuccessHandler successHandler() {
    SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
    successHandler.setTargetUrlParameter("/succeslogin");
    return successHandler;
}

and use it in your configuration:

http.formLogin()
    .loginProcessingUrl("/login")
    .permitAll()
    .usernameParameter("email")
    .passwordParameter("pass")
    .successHandler(successHandler())

after that you can create controller, that will send response from speciafied url:

@Controller
@RequestMapping("/sucesslogin")
public class SuccessLoginController{

     @RequestMapping(method = RequestMethod.POST)
     public String index(ModelMap model, Principal principal){
         //here you can return view with response
     }

}

Of cause, you can return not only view, but JSON response (using @ResponseBody annotation), or something else, depends on you front-end. Hope this will be helpful.

这篇关于Spring Boot-登录后返回用户对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆