答案 0 :(得分:40)
这可以通过弹簧安全性以下列方式完成(半伪代码):
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);
}
}
更新:仅包含注册后如何创建会话
答案 1 :(得分:12)
在Servlet 3+中,您可以只执行request.login("username","password")
,如果成功,则重定向到您想要的任何页面。您可以为自动注销执行相同的操作。
以下是文档部分的链接:http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#servletapi-3
答案 2 :(得分:8)
只是对第一个回复如何自动验证authenticationManager的评论。
在applicantion-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";
答案 3 :(得分:2)
由于转发是内部的,因此用户会在同一请求中注册并登录。
如果您的注册表单不包含正确的用户名和密码参数名称,请将修改后的请求版本(使用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 强>
答案 4 :(得分:1)
使用SecurityContextHolder.getContext()。setAuthentication(Authentication)完成工作,但它将绕过spring安全过滤器链,这将产生安全风险。
例如让我们说在我的情况下,当用户重置密码时,我希望他在没有再次登录的情况下进入仪表板。当我使用上述方法时,它会将我带到仪表板,但它绕过了我已应用的并发过滤器以避免并发登录。这是完成工作的代码片段:
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安全过滤器链。
希望有所帮助
答案 5 :(得分:1)
我合并了相同的场景,下面是代码片段。要获取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 :(得分:0)
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>
答案 7 :(得分:0)
这是上述问题的答案 在控制器中:
@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中,所以没有意识到为什么逻辑在代码运行时没有工作......并且控制台上没有任何错误或异常。所以,如果你不把它放在尝试捕捉你不会得到不良凭据的例外。
答案 8 :(得分:0)
这是Servlet 3+集成的替代方案。如果您使用Spring Security的表单登录,那么您可以简单地委派您的登录页面。例如:
cd /var/lib
sudo chown --from=mysql <my_username> mysql* -R
sudo rm -rf mysql*
假设您的表单中有sudo apt-get install mysql-server
和@PostMapping("/signup")
public String signUp(User user) {
// encode the password and save the user
return "forward:/login";
}
个字段,那么&#39;转发&#39;将发送这些参数,Spring Security将使用这些参数进行身份验证。
我通过这种方法获得的好处是,您不会复制username
password
(下面的示例安全设置)。它还通过不需要formLogin
参数来清理控制器。
defaultSuccessUrl
答案 9 :(得分:-1)
我不确定您是否要求这样做,但在Spring Security配置中,您可以添加“remember-me”标签。这将管理您客户端中的cookie,因此下次(如果cookie未过期)将自动记录。
<http>
...
<remember-me />
</http>