spring 注册成功后自动登录

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3813028/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 04:09:16  来源:igfitidea点击:

Auto login after successful registration

springspring-security

提问by Mahmoud Saleh

hey all i want to make an auto login after successful registration in spring meaning: i have a protected page which requires login to access them and i want after registration to skip the login page and make an auto login so the user can see that protected page, got me ? i am using spring 3.0 , spring security 3.0.2 how to do so ?

嘿,我想在 spring 成功注册后自动登录 意思是:我有一个受保护的页面,需要登录才能访问它们,我想在注册后跳过登录页面并进行自动登录,以便用户可以看到该受保护的页面,明白我了吗?我正在使用 spring 3.0,spring security 3.0.2 怎么做?

回答by Spring Monkey

This can be done with spring security in the following manner(semi-psuedocode):

这可以通过以下方式(半伪代码)使用 spring 安全性完成:

import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;

@Controller
public class SignupController
{

    @Autowired
    RequestCache requestCache;

    @Autowired
    protected AuthenticationManager authenticationManager;

    @RequestMapping(value = "/account/signup/", method = RequestMethod.POST)
    public String createNewUser(@ModelAttribute("user") User user, BindingResult result,  HttpServletRequest request, HttpServletResponse response) {
        //After successfully Creating user
        authenticateUserAndSetSession(user, request);

        return "redirect:/home/";
    }

    private void authenticateUserAndSetSession(User user, HttpServletRequest request) {
        String username = user.getUsername();
        String password = user.getPassword();
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);

        // generate session if one doesn't exist
        request.getSession();

        token.setDetails(new WebAuthenticationDetails(request));
        Authentication authenticatedUser = authenticationManager.authenticate(token);

        SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
    }
}

Update: to only contain how to create the session after the registration

更新:仅包含注册后如何创建会话

回答by Henok T

In Servlet 3+ you can simply do request.login("username","password")and if successful, redirect to whatever page you want. You can do the same for auto logout.

在 Servlet 3+ 中,你可以简单地做request.login("username","password"),如果成功,重定向到你想要的任何页面。您可以对自动注销执行相同的操作。

Here is the link to the section of the documentation that talks about this: http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#servletapi-3

这是讨论此问题的文档部分的链接:http: //docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#servletapi-3

回答by user844085

Just a comment to the first reply on how to autowire authenticationManager.

只是对关于如何自动装配 authenticationManager 的第一个回复的评论。

You need to set an alias when you declare authentication-manager in either your applicantion-servlet.xml or applicationContext-security.xml file:

当你在你的申请者-servlet.xml 或 applicationContext-security.xml 文件中声明 authentication-manager 时,你需要设置一个别名:

<authentication-manager alias="authenticationManager>
    <authentication-provider>
        <user-service>
            <user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
            <user name="bob" password="bobspassword" authorities="ROLE_USER" />
        </user-service>
    </authentication-provider>
</authentication-manager>

Also, when you authenticate, it may throw an AuthenticationException, so you need to catch it:

此外,当您进行身份验证时,它可能会抛出 AuthenticationException,因此您需要捕获它:

UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getEmail(), user.getPassword());
request.getSession();

token.setDetails(new WebAuthenticationDetails(request));

try{
    Authentication auth = authenticationManager.authenticate(token);

    SecurityContextHolder.getContext().setAuthentication(auth);
} catch(Exception e){
        e.printStackTrace();
}

return "redirect:xxxx.htm";

回答by andy

  1. Configure web.xml to allow Spring Security to handle forwards for a login processing url.
  2. Handle registration request, e.g. create user, update ACL, etc.
  3. Forward it with username and password to login processing url for authentication.
  4. Gain benefits of entire Spring Security filter chain, e.g. session fixation protection.
  1. 配置 web.xml 以允许 Spring Security 处理登录处理 url 的转发。
  2. 处理注册请求,例如创建用户、更新ACL等。
  3. 将其与用户名和密码一起转发到登录处理 url 进行身份验证。
  4. 获得整个 Spring Security 过滤器链的好处,例如会话固定保护。

Since forwards are internal, it will appear to the user as if they are registered and logged in during the same request.

由于转发是内部的,因此在用户看来就好像它们是在同一请求期间注册和登录的。

If your registration form does not contain the correct username and password parameter names, forward a modified version of the request (using HttpServletRequestWrapper) to the Spring Security login endpoint.

如果您的注册表单不包含正确的用户名和密码参数名称,请将请求的修改版本(使用HttpServletRequestWrapper)转发到 Spring Security 登录端点。

In order for this to work, you'll have to modify your web.xml to have the Spring Security filter chain handle forwards for the login-processing-url. For example:

为了使其工作,您必须修改 web.xml 以使 Spring Security 过滤器链处理login-processing-url. 例如:

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<!-- Handle authentication for normal requests. -->
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<!-- Handle authentication via forwarding for internal/automatic authentication. -->
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/login/auth</url-pattern>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

Source: mohchi blog

来源:mohchi博客

回答by Rahul Gupta

I incorporated the same scenario, below is the code snippet. To get the instance of AuthenticationManager, you will need to override the authenticationManagerBean() method of WebSecurityConfigurerAdapter class

我合并了相同的场景,下面是代码片段。要获取 AuthenticationManager 的实例,您需要覆盖 WebSecurityConfigurerAdapter 类的 authenticationManagerBean() 方法

SecurityConfiguration(extends WebSecurityConfigurerAdapter)

SecurityConfiguration(扩展 WebSecurityConfigurerAdapter)

@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}

Controller

控制器

    @Autowired
    protected AuthenticationManager authenticationManager;

    @PostMapping("/register")
    public ModelAndView registerNewUser(@Valid User user,BindingResult bindingResult,HttpServletRequest request,HttpServletResponse response) {
        ModelAndView modelAndView = new ModelAndView();
        User userObj = userService.findUserByEmail(user.getEmail());
        if(userObj != null){
            bindingResult.rejectValue("email", "error.user", "This email id is already registered.");
        }
        if(bindingResult.hasErrors()){
            modelAndView.setViewName("register");
            return modelAndView;
        }else{
            String unEncodedPwd = user.getPassword();
            userService.saveUser(user);
            modelAndView.setViewName("view_name");
            authWithAuthManager(request,user.getEmail(),unEncodedPwd);
        }   
        return modelAndView;
    }


    public void authWithAuthManager(HttpServletRequest request, String email, String password) {
        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(email, password);
        authToken.setDetails(new WebAuthenticationDetails(request));
        Authentication authentication = authenticationManager.authenticate(authToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }

回答by Ankit Pandoh

Using SecurityContextHolder.getContext().setAuthentication(Authentication) gets the job done but it will bypass the spring security filter chain which will open a security risk.

使用 SecurityContextHolder.getContext().setAuthentication(Authentication) 可以完成工作,但它会绕过 spring 安全过滤器链,这将打开安全风险。

For e.g. lets say in my case when user reset the password, I wanted him to take to the dashboard without login again. When I used the above said approach, it takes me to dashboard but it bypassed my concurrency filter which I have applied in order to avoid concurrent login. Here is the piece of code which does the job:

例如,在我的情况下,当用户重置密码时,我希望他无需再次登录即可进入仪表板。当我使用上述方法时,它会将我带到仪表板,但它绕过了我为避免并发登录而应用的并发过滤器。这是完成这项工作的一段代码:

UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(empId, password);
Authentication auth = authenticationManager.authenticate(authToken);
SecurityContextHolder.getContext().setAuthentication(auth);

Use login-processing-url attribute along with a simple change in web.xml

使用 login-processing-url 属性以及 web.xml 中的简单更改

security-xml

安全-xml

<form-login login-page="/login" 
            always-use-default-target="false" 
            default-target-url="/target-url" 
            authentication-failure-url="/login?error"
            login-processing-url="/submitLogin"/>

web.xml

网页.xml

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/submitLogin</url-pattern>
    <dispatcher>FORWARD</dispatcher>
 </filter-mapping>

By adding this piece of code in web.xml actually does the job of forwarding your explicit forward request which you will make during auto login and passing it to the chain of spring security filters.

通过在 web.xml 中添加这段代码,实际上可以转发您在自动登录期间发出的显式转发请求,并将其传递给 spring 安全过滤器链。

Hope it helps

希望能帮助到你

回答by Dillon Ryan Redding

This is an alternative to the Servlet 3+ integration. If you're using Spring Security's form login, then you can simply delegate to your login page. For example:

这是 Servlet 3+ 集成的替代方案。如果您使用 Spring Security 的表单登录,那么您可以简单地委托给您的登录页面。例如:

@PostMapping("/signup")
public String signUp(User user) {
    // encode the password and save the user
    return "forward:/login";
}

Assuming you have usernameand passwordfields in your form, then the 'forward' will send those parameters and Spring Security will use those to authenticate.

假设您的表单中有usernamepassword字段,那么“转发”将发送这些参数,Spring Security 将使用这些参数进行身份验证。

The benefit I found with this approach is that you don't duplicate your formLogin's defaultSuccessUrl(example security setup below). It also cleans up your controller by not requiring a HttpServletRequestparameter.

我发现这种方法的好处是您不会复制formLogin's defaultSuccessUrl(下面的示例安全设置)。它还通过不需要HttpServletRequest参数来清理您的控制器。

@Override
public void configure(HttpSecurity http) {
    http.authorizeRequests()
            .antMatchers("/", "/signup").permitAll()
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/login")
            .defaultSuccessUrl("/home", true)
            .permitAll();
}

回答by Yogesh Devgun

This is answer to above question In Controller:

这是对控制器中上述问题的回答

@RequestMapping(value = "/registerHere", method = RequestMethod.POST)
    public ModelAndView registerUser(@ModelAttribute("user") Users user, BindingResult result,
            HttpServletRequest request, HttpServletResponse response) {
        System.out.println("register 3");

        ModelAndView mv = new ModelAndView("/home");
        mv.addObject("homePagee", "true");

        String uname = user.getUsername();

        if (userDAO.getUserByName(uname) == null) {

            String passwordFromForm = user.getPassword();
            userDAO.saveOrUpdate(user);

            try {
                authenticateUserAndSetSession(user, passwordFromForm, request);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }


        }

        System.out.println("register 4");

        log.debug("Ending of the method registerUser");
        return mv;
    }

Further above method in controller is defined as:

控制器中的上述方法进一步定义为:

`private void authenticateUserAndSetSession(Users user, String passwor`dFromForm, HttpServletRequest request){

        String username = user.getUsername();
        System.out.println("username:  " + username + " password: " + passwordFromForm);                        

        UserDetails userDetails = userDetailsService.loadUserByUsername(user.getUsername());

        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, passwordFromForm, userDetails.getAuthorities());
        request.getSession();

        System.out.println("Line Authentication 1");

        usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetails(request));

        System.out.println("Line Authentication 2");

        Authentication authenticatedUser = authenticationManager.authenticate(usernamePasswordAuthenticationToken);

        System.out.println("Line Authentication 3");


        if (usernamePasswordAuthenticationToken.isAuthenticated()) {
            SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
            System.out.println("Line Authentication 4");

        }

     request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());// creates context for that session.

        System.out.println("Line Authentication 5");

        session.setAttribute("username", user.getUsername());

        System.out.println("Line Authentication 6");

        session.setAttribute("authorities", usernamePasswordAuthenticationToken.getAuthorities());

        System.out.println("username:  " + user.getUsername() + "password: " + user.getPassword()+"authorities: "+ usernamePasswordAuthenticationToken.getAuthorities());

        user = userDAO.validate(user.getUsername(), user.getPassword());
        log.debug("You are successfully register");

    }

Other answers didnt suggest to put it in try/catch so one does not realize why logic is not working as code runs...and nothing is there neither error or exception on console. So if you wont put it in try catch you wont get exception of bad credentials.

其他答案并没有建议将它放在 try/catch 中,所以人们没有意识到为什么在代码运行时逻辑不起作用......控制台上没有任何错误或异常。所以如果你不把它放在 try catch 中,你就不会得到错误凭据的例外。

回答by gerrytan

Spring Monkey's answer works greatbut I encountered a tricky problem when implementing it.

Spring Monkey 的答案效果很好,但我在实现它时遇到了一个棘手的问题。

My problem was because I set the registration page to have "no security", eg:

我的问题是因为我将注册页面设置为“没有安全性”,例如:

<http pattern="/register/**" security="none"/>

I think this causes no SecurityContext initialized, and hence after user registers, the in-server authentication cannot be saved.

我认为这会导致没有初始化 SecurityContext,因此在用户注册后,无法保存服务器内身份验证。

I had to change the register page bypass by setting it into IS_AUTHENTICATED_ANONYMOUSLY

我不得不通过将其设置为 IS_AUTHENTICATED_ANONYMOUSLY 来更改注册页面绕过

<http authentication-manager-ref="authMgr">
  <intercept-url pattern="/register/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
  ...
</http>

回答by sinuhepop

I'm not sure if you are asking for this, but in your Spring Security configuration you can add a "remember-me" tag. This will manage a cookie in your client, so next time (if the cookie hasn't expired) you'll be logged automatically.

我不确定您是否要求这样做,但在您的 Spring Security 配置中,您可以添加“记住我”标签。这将管理您客户端中的 cookie,因此下次(如果 cookie 尚未过期)您将被自动记录。

<http>
    ...
    <remember-me />
</http>