注册成功后自动登录

Posted

技术标签:

【中文标题】注册成功后自动登录【英文标题】:Auto login after successful registration 【发布时间】:2011-04-18 07:14:11 【问题描述】:

大家好 我想在春季成功注册后进行自动登录 意义: 我有一个受保护的页面,需要登录才能访问它们 我想在注册后跳过登录页面并进行自动登录,这样用户就可以看到受保护的页面,明白了吗? 我正在使用弹簧 3.0,弹簧安全 3.0.2 怎么做?

【问题讨论】:

【参考方案1】:

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

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);
    

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

【讨论】:

不正确,我已经知道登录页面,但需要登录才能看到,我不想进入登录页面并想要进行内部自动登录,明白了吗?跨度> 我已经更新了注册后自动登录的代码。 我遇到了以下异常??? org.springframework.security.authentication.BadCredentialsException:错误的凭据 上一个异常已解决,但我得到以下异常 org.springframework.security.access.AccessDeniedException: Access is denied more details here:***.com/questions/3923296/… @ShravanRamamurthy 在我的 Spring Security 集成 extjs 应用程序中实现此功能后,我遇到了同样的问题。它仅在用新认证的安全上下文替换会话中现有的 spring 安全上下文密钥后才对我有用。 request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());【参考方案2】:

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

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

【讨论】:

底层方法基本上是在底层实现***.com/a/3815189/1178781。所以,这对我来说非常有效! 完美运行,并且比任何其他答案都简单得多。谢谢!【参考方案3】:

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

您需要在您的申请-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>

另外,当你进行身份验证时,它可能会抛出一个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";

【讨论】:

【参考方案4】:
    配置 web.xml 以允许 Spring Security 处理登录处理 url 的转发。 处理注册请求,例如创建用户、更新 ACL 等。 将用户名和密码转发到登录处理url进行身份验证。 获得整个 Spring Security 过滤器链的好处,例如会话固定保护。

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

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

为了使其工作,您必须修改您的 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

【讨论】:

【参考方案5】:

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

SecurityConfiguration(扩展 WebSecurityConfigurerAdapter)

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

控制器

    @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);
    

【讨论】:

【参考方案6】:

使用 SecurityContextHolder.getContext().setAuthentication(Authentication) 可以完成工作,但它会绕过弹簧安全过滤器链,这会带来安全风险。

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

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

使用 login-processing-url 属性以及 web.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

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

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

希望对你有帮助

【讨论】:

【参考方案7】:

Spring Monkey's answer works great 但是在实现的时候遇到了一个棘手的问题。

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

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

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

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

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

【讨论】:

【参考方案8】:

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

@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;
    

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

`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");

    

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

【讨论】:

【参考方案9】:

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

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

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

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

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

【讨论】:

【参考方案10】:

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

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

【讨论】:

这不是你要问的

以上是关于注册成功后自动登录的主要内容,如果未能解决你的问题,请参考以下文章

CAS单点登录,怎么实现注册后自动登录。用java实现

用户注册后Django自动登录(1.4)

Symfony2 / SonataUserBundle - 注册后自动登录

杜鹃加速器的软件界面及功能介绍

登陆界面代码

Parse Login iOS – 注册后不登录用户