如何在Spring Boot中设置自定义登录?

huangapple go评论93阅读模式
英文:

How do I set up a custom login with Spring Boot?

问题

Sure, here's the translated content of your provided text:

Question
我如何在Spring Boot中设置自定义登录?我需要使用我已有的一个遗留应用程序的相同连接方法。

Things to know before I explain
在我解释之前需要知道的事情:

  • 我有一个JavaFX应用程序,它使用一个PHP网站作为代理/登录来连接数据库。很明显,这个JavaFX应用程序已经定义了User类。
  • 数据库按公司(用户组)进行分隔,登录过程基本上是检索用户对象以及它应该连接到哪个数据库。
  • JavaFX应用程序使用Web服务登录,并检索特定用户的数据库URL。
  • JavaFX应用程序使用数据库URL直接访问数据库。

或者,简化一下:用户输入登录名和密码,然后点击“登录”->应用程序访问Web主机,将数据发送到某个PHP文件,并通过JASPYR以及HTTPS加密获取数据库URL和数据。一旦数据返回,我们解密它并直接登录到数据库。

  • 我正在构建一个与这个遗留应用程序一起使用的Spring Boot应用程序。

Where Am I stuck?
我已经构建了一个Spring Boot Maven项目,并且正在阅读关于Spring Boot的很多资料。我的第一步是创建一个行为类似于遗留应用程序的登录页面。

目前,我正在使用以下InMemorySecurityConfig:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;

@Configuration
public class InMemorySecurityConfig {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user").password("{noop}123").roles("USER")
                .and()
                .withUser("admin").password("{noop}123").roles("ADMIN");
    }
}

我不知道如何开始。我认为我必须找到一种方法来定义正确的User模型,然后使用一个类来登录,实际上允许我手动登录。

以下是我在JavaFX应用程序中使用的遗留类:

public JSONObject login(String usuario, String senha) throws MalformedURLException, IOException {
    // ...
}

@Override
protected Task<JSONObject> createTask() {
    // ...
}

我如何开始?对于如何开始的任何提示都会非常感谢。

我预期我必须以某种方式告诉Spring Boot要使用哪个User类,告诉Spring不要立即连接到数据库,而是等待数据库信息由登录页面检索,并以某种方式使用Spring进行登录。

英文:

Question
How do I set up a custom login with Spring Boot? I need to use the same connection method of a legacy app I have.

Things to know before I explain

  • I have a javafx App that connects to a data base using a php website
    as proxy/Login Obviously, this javafx app has the User class already
    defined.
  • The Database is separated by company(group of users), the login process basically retrieves the user object and to which database it should connect.
  • The javafx application logs in with the web service and retrieves
    the database URL for that specific user.
  • The javafx application uses the database URL to access a database
    directly.

Or, to simplify: The user put the login and password and click LOGIN -> The app, goes to the webhost, sends the data to a certain php file and requests the database url and data that comes ENCRYPTED through JASPYR and it also comes through https. Once the data is returned, we decrypt it and login to the database directly.

  • Im building a SpringBoot application to work with this legacy app.

Where Am I stuck?

I have built a Spring boot maven project and im reading a lot about Spring boot. My first step is to create a login page that behaves as the legacy app.

Currently, Im using a InMemorySecurityConfig as follows:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
 
@Configuration
public class InMemorySecurityConfig {
     
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser(&quot;user&quot;).password(&quot;{noop}123&quot;).roles(&quot;USER&quot;)
                .and()
                .withUser(&quot;admin&quot;).password(&quot;{noop}123&quot;).roles(&quot;ADMIN&quot;);
    }
}

I dont know how to start. I think I have to find away to define the correct User model and then use a class to login that actually allows me to manually login.

Here is the legacy class that I use on my javafx App below.

public JSONObject login(String usuario, String senha) throws MalformedURLException, IOException {
        int timeout = 10;
        RequestConfig config = RequestConfig.custom()
                .setConnectTimeout(timeout * 1000)
                .setConnectionRequestTimeout(timeout * 1000)
                .setContentCompressionEnabled(true)
                .setAuthenticationEnabled(true)
                .setSocketTimeout(timeout * 1000)
                .build();
 
        CloseableHttpClient httpclient = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
        HttpPost httppost = new HttpPost(Settings.LOGIN_URL);
 
        int CONNECTION_TIMEOUT_MS = timeout * 1000; // Timeout in millis.
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(CONNECTION_TIMEOUT_MS)
                .setConnectTimeout(CONNECTION_TIMEOUT_MS)
                .setContentCompressionEnabled(true)
                .setAuthenticationEnabled(true)
                .setSocketTimeout(CONNECTION_TIMEOUT_MS)
                .build();
 
        httppost.setConfig(requestConfig);
 
        // Request parameters and other properties.
        ArrayList&lt;NameValuePair&gt; params = new ArrayList&lt;NameValuePair&gt;(2);
        params.add(new BasicNameValuePair(&quot;usuario&quot;, usuario)); // user
        params.add(new BasicNameValuePair(&quot;senha&quot;, senha)); // password
        httppost.setEntity(new UrlEncodedFormEntity(params, &quot;UTF-8&quot;));
 
        CloseableHttpResponse execute = null;
 
        try {
            execute = httpclient.execute(httppost);
        } catch (Exception ex) {
 
            try {
                httppost.abort();
                if (execute != null) {
                    execute.close();
                }
            } catch (Exception x) {
                ErrorLogger.log(x);
            }
            throw ex;
 
        }
        HttpEntity entity = execute.getEntity();
 
        if (entity != null) {
            JSONObject json = JsonTools.readJson(entity.getContent());
            
            return json;
        }
 
        return null;
    }

@Override
    protected Task&lt;JSONObject&gt; createTask() {
 
        return new Task&lt;JSONObject&gt;() {
            @Override
            protected JSONObject call() throws InterruptedException, IOException {
                StringProperty usuario = getUserName();
                StringProperty senha = getPassword();
 
                LoginDAO loginDAO = new LoginDAO();
                JSONObject login = loginDAO.login(MyTools.encodeToBase64(usuario.get()), MyTools.encodeToBase64(senha.get()));
 
                String db_url = login.getString(&quot;db_url&quot;);
                String db_username = login.getString(&quot;db_username&quot;);
                String db_password = login.getString(&quot;db_password&quot;);
                String nomeEmpresa = login.getString(&quot;nomeEmpresa&quot;);
 
                int idUsuario = login.getInt(&quot;idUsuario&quot;);
                String nomeDoUsuario = login.getString(&quot;nomeUsuario&quot;);
                int idTunnel = login.getInt(&quot;idTunnel&quot;);
 
                Settings.setDb_password(db_password);
                Settings.setDb_username(db_username);
                Settings.setDb_url(db_url);
                Settings.setDb_empresa(nomeEmpresa);
 
                //Connect to the data base 
                HibernateUtil.init();
 
 
                return login;
            }
        };
 
    }

How do I start? Any tips on how to start is greatly appreciated.

Im expecting that I have to somehow tell spring boot which User class to use, to tell spring to NOT instantly connect to the database and wait for the database info to be retrieved by the login page, and a way to login using spring.

答案1

得分: 2

Spring Boot基于类似以下的http端点:

@RestController
@RequestMapping("/api/login")
public class LoginController {

    private final LoginService loginService;

    @GetMapping
    public ObjectYouWantReturn returnDatabaseURL(@RequestBody DtoCredentials dto) {
        return loginService.returnDatabaseURL(dto.getUsername(), dto.getPassword());
    }
}

您的客户端必须将DtoCredentials发送到https://your.host/api/login。然后服务器将向您的客户端返回受保护的数据。您需要实现一种机制来验证用户的凭据。

此类将通过用户名加载UserDetailsImpl。您可以使用以下类从数据库加载数据,或者仅创建一个包含用户的List或类似的数据结构。

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Override
    public UserDetailsImpl loadUserByUsername(String username) {
        //在这里您必须创建一个机制,以返回UserDetails中的用户凭据
    }
}

UserDetails是基本的DTO,详见文档

public class UserDetailsImpl implements UserDetails {
    //在这里实现UserDetails指定的方法
}

这是一个Service。在Spring Boot中,将逻辑与控制器分离是一个很好的实践。在returnDatabaseURL()方法中,我们正在检查凭证是否正确。如果正确,服务器将返回数据给客户端;如果不正确,我们可以抛出ResponseStatusException(HttpStatus.NOT_FOUND)或其他任何异常。

@Service
public class LoginService {

    /*Spring Boot应该会自动通过@Service注解注入UserDetailsServiceImpl*/
    private final UserDetailsServiceImpl userDetails;

    public LoginService(UserDetailsServiceImpl userDetails) {
        this.userDetails = userDetails;
    }

    public ObjectYouWantReturn returnDatabaseURL(String username, String password) {
        if (userDetails.loadUserByUsername(username) != null &&
            userDetails.loadUserByUsername(username).getPassword().equals(password)) {
            return new ObjectYouWantReturn(/*返回到用户的数据库URL或其他想返回给用户的内容*/); 
        }
    }
}

service中验证用户不是最佳方法,建议在过滤器中验证用户。但是过滤器是一个稍微高级的问题。

DtoCredentials的基本实现:

public class DtoUsernamePassword implements Serializable {

    @NotBlank
    private final String username;

    @NotBlank
    private final String password;

    public DtoUsernamePassword(@JsonProperty("username") @NotBlank String username,
                               @JsonProperty("password") @NotBlank String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }
}

需要的Jackson依赖:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.11.2</version>
</dependency>

希望阅读完后您能对Spring Boot有更好的理解(因为我看到您在Spring Boot方面还是新手)。这不是完全的实现。如果我的回答不能满足您的要求,就把它当作解释Spring Boot工作原理的一次尝试。

英文:

Spring Boot base on http endpoints like this:

@RestController
@RequestMapping(&quot;/api/login&quot;)
public class LoginController {

    private final LoginService loginService;

    @GetMapping
    public ObjectYouWantReturn returnDatabaseURL(@RequestBody DtoCredentials dto) {
        return loginService.returnDatabaseURL(dto.getUsername, dto.getPassword);
    }
}

Your client must send DtoCredentials to https://your.host/api/login. Then server will return secured data to your client. You need to implement mechanism to validation credentials from a user.

This class will load a UserDetailsImpl by username. You can use below class for load data from a database or simply create a List or something with users.

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Override
    public UserDetailsImpl loadUserByUsername(String username) {
        //here you have to create mechanism returning user credentials in UserDetails
    }
}

UserDetails is basic DTO, look at the documentation

public class UserDetailsImpl implements UserDetails {
    //implement here methods specified by UserDetails
}

And this is Service. In Spring Boot a good practice is separating logic from controllers. In method returnDatabaseURL() we are checking are the credentials correctly. If they are, the server returns data to client, or if not, we can throw ResponseStatusException(HttpStatus.NOT_FOUND) of anything else.

@Service
public class LoginService {

    /*Spring Boot should automatically inject UserDetailsServiceImpl because we 
    annotated it by @Service annotation*/
    private final UserDetailsServiceImpl userDetails;

    public LoginService(UserDetailsServiceImpl userDetails) {
        this.userDetails = userDetails;
    }
    
    public ObjectYouWantReturn returnDatabaseURL(String username, String password) {
        if (userDetails.loadUserByUsername(username) != null &amp;&amp;
            userDetails.loadUserByUsername(username).getPassword().equals(password)) {
            return new ObjectYouWantReturn(/*URL to database or anything you want to 
                                           return to user*/); 
        }
    }
}

Validating users in the service is not the best way, it is recommended that validate user in filter. But filters is a little bit more advanced issue.

Basic implementation of DtoCredentials:

public class DtoUsernamePassword implements Serializable {

    @NotBlank
    private final String username;

    @NotBlank
    private final String password;

    public DtoUsernamePassword(@JsonProperty(&quot;username&quot;) @NotBlank String username,
                               @JsonProperty(&quot;password&quot;) @NotBlank String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }
}

Needed Jackson dependency:

&lt;dependency&gt;
    &lt;groupId&gt;com.fasterxml.jackson.core&lt;/groupId&gt;
    &lt;artifactId&gt;jackson-core&lt;/artifactId&gt;
    &lt;version&gt;2.11.2&lt;/version&gt;
&lt;/dependency&gt;

I hope that after read it you will understand Spring Boot a bit more (because as I see you are new in Spring Boot). It's not a completely implementation. If my answer don't satisfying you, treat it as a loose attempt to explain how does Spring Boot work.

huangapple
  • 本文由 发表于 2020年10月26日 20:48:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/64537432.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定