Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.6k views
in Technique[技术] by (71.8m points)

jsf 2 - How to validate a login inside a bean using spring security?

So I'm learning Spring and I'm using JSF with PrimeFaces.

My question:

I would like to know how (if possible) to authenticate and authorize user credentials using a boolean function in a bean, like this:

public boolean check() {
  boolean isLoginValid = false;
  if (//run something like j_spring_security_check) {
      //obtain user authorizations....
      isLoginValid = true;
  }
  return isLoginValid;
}

The reason:

public void doLogin() {
    RequestContext context = RequestContext.getCurrentInstance();

    FacesMessage msg;
    boolean loggedIn;

    if (check() //would use the functin here) {
        loggedIn = true;
        msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Welcome", usuario);
    } else {
        loggedIn = false;
        msg = new FacesMessage(FacesMessage.SEVERITY_WARN, "Login Error", "Invalid credentials");
    }

    FacesContext.getCurrentInstance().addMessage(null, msg);
    context.addCallbackParam("loggedIn", loggedIn);
    context.addCallbackParam("authorization", this.auth #obtained in check());
}

This way I could have the boolean sent to my button via ajax, like this:

<p:commandButton id="loginButton" value="Login" update=":growl"   
                          actionListener="#{loginBean.doLogin}"   
                          oncomplete="handleLoginRequest(xhr, status, args)"/>

function handleLoginRequest(xhr, status, args) {
            if(args.validationFailed || !args.loggedIn) {  
                jQuery('#dialog').effect("shake", { times:3 }, 100);
            } else {
                jQuery('#dialog').effect("shake", { times:1 }, 200);
                //And redirect to the right page.
            }  
        }

Thanks!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

With the help of SpringBeanFacesELResolver, you can have the managed property Authentication Manager resolved from the Spring Application Context and JSF's IOC injects the bean to your backing bean.

For this add SpringBeanFacesELResolver to your faces-config.xml like this:

<application>
    <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>

and then in your backing bean you can authenticate the passed Authentication object like below:

public class LoginBean implements Serializable {
    private static final long serialVersionUID = 1L;
    private String userName;
    private String password;
    @ManagedProperty(value="#{authenticationManager}")
        private AuthenticationManager authenticationManager;
        public AuthenticationManager getAuthenticationManager() {
        return authenticationManager;
    }

    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        this.authenticationManager= authenticationManager;
    }

    public String doLogin() {
        Authentication authenticationRequestToken =
              new UsernamePasswordAuthenticationToken( userName, password );
        //authentication action
        try {
            Authentication authenticationResponseToken =
                authenticationManager.authenticate(authenticationRequestToken);
            SecurityContextHolder.getContext().setAuthentication(authenticationResponseToken);
            //ok, test if authenticated, if yes reroute
            if (authenticationResponseToken.isAuthenticated()) {
                //lookup authentication success url, or find redirect parameter from login bean
                return "/secure/examples";
            }
        } catch (BadCredentialsException badCredentialsException) {
            FacesMessage facesMessage =
                new FacesMessage("Login Failed: please check your username/password and try again.");
            FacesContext.getCurrentInstance().addMessage(null,facesMessage);
        } catch (LockedException lockedException) {
            FacesMessage facesMessage =
                new FacesMessage("Account Locked: please contact your administrator.");
            FacesContext.getCurrentInstance().addMessage(null,facesMessage);
        } catch (DisabledException disabledException) {
            FacesMessage facesMessage =
                new FacesMessage("Account Disabled: please contact your administrator.");
            FacesContext.getCurrentInstance().addMessage(null,facesMessage);
        }

        return null;
    }
}

See also:

UPDATE

If you are unable to use the @ManagedProperty for some reason. You can try to use Spring @Autowired annotation by making the JSF ManagedBean into a Spring-managed Component. For that annotate the bean like this:

@Component
@Scope("request")
public class LoginController implements Serializable {
    @Autowired
    private AuthenticationManager authenticationManager;
        //bean getters and setters

and add component-scan element to your Spring Application context like this:

<context:component-scan base-package="com.examples"/>

For you question regarding using authentication-success-handler-ref, I am afraid you can use that since we are manually doing the authentication. If your requirement is to just forward to appropriate url based of user role. You can do something like this:

if (authenticationResponseToken.isAuthenticated()) {
   String userTargetUrl = "/general/main";
   String adminTargetUrl = "/secure/examples";
   Set<String> roles = AuthorityUtils.authorityListToSet(authenticationResponseToken.getAuthorities());
   if (roles.contains("ROLE_ADMIN")) {
      return adminTargetUrl;
   }
   else if(roles.contains("ROLE_USER")) {
      return userTargetUrl;
   }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share

2.1m questions

2.1m answers

63 comments

56.5k users

...