手动 Spring 安全实现,通过角度和密码编码调用

Posted

技术标签:

【中文标题】手动 Spring 安全实现,通过角度和密码编码调用【英文标题】:Manual Spring security implementation with a call from angular and password encoded 【发布时间】:2017-05-26 01:36:26 【问题描述】:

我很抱歉我的英语不好..

我正在使用 Spring Boot、Spring Security 模块和 Angular。我也有一个自定义数据库。

我改变了我所有的项目架构。之前,我在我的 html 中使用登录表单调用 thymeleaf:th:action="@/login"。现在,我删除了 thymeleaf,所以我用 AngularJS 实现了一个简单的表单。

我想做的是:

单击我的 HTML 页面中的按钮 确定 调用角度函数OK 使用用户名和密码作为参数执行 POST 请求 OK 使用@RequestMapping(value="/login" method=RequestMethod.POST) 注解调用Java 控制器OK 调用我在 SecurityConfig.java 中的 configAuthentication()。

之前我在使用thymeleaf的时候,这个函数是通过拦截请求自动调用的。但现在我需要手动调用它。我该怎么做?

我在这里发布我的部分代码:

我的 login.html 中的表单

<form autocomplete="off">
     <label>'login.username' | translate</label>
     <input class="form-control" type="text" name="username" ng-change="message = false" ng-model="username" required/>
      <label>'login.password' | translate</label>
      <input class="form-control" type="password" name="password" ng-change="message = false" ng-model="password" required/>
      <button type="submit" class="btn btn-default" ng-click="login()">'login.button' | translate</button>
 </form>

我在 login.js 中的 Angular 函数

$scope.login = function()
        var dataToSend = 
            username : $scope.username,
            password : $scope.password
        
        $http.post('/login', dataToSend).success(function()
            alert("ok");
        ).error(function () 
            alert("skdjs");
        )
    

我的 UserController.java 中的 java 方法(我需要用你的提议来实现这个方法)

@RequestMapping(value="/login", method = RequestMethod.POST)
public JSONObject login(HttpServletRequest request, HttpServletResponse response, @RequestBody User user) 


我可以轻松获得密码和用户名,但我没有 getAuthorities 方法。 如您在我的 SecurityConfig.java

中所见,我有一个加密密码

有关注销的信息,我有这个,它可以工作

@RequestMapping(value="/user/logout", method = RequestMethod.GET)
public String logoutPage (HttpServletRequest request, HttpServletResponse response) 
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    if (auth != null)
        new SecurityContextLogoutHandler().logout(request, response, auth);
    
    return "redirect:/login?logout";

最后,我的文件 SecurityConfig.java 和我的方法 configAuthentication 没有被调用。

package betizy.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;

import javax.sql.DataSource;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter 


@Autowired
DataSource dataSource;

@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception 
    System.out.println("djfkdjfdkfjkd");

    auth.jdbcAuthentication().dataSource(dataSource)
            .passwordEncoder(passwordEncoder())
            .usersByUsernameQuery(
                    "select use_username, use_password, use_enabled from use_user where use_username=?")
            .authoritiesByUsernameQuery(
                    "select use_username, usr_role from usr_user_role, use_user where use_id = usr_use_id and use_username=?");


@Bean
public PasswordEncoder passwordEncoder()
    PasswordEncoder encoder = new BCryptPasswordEncoder();
    return encoder;



@Override
protected void configure(HttpSecurity http) throws Exception 
    http.authorizeRequests()
            //.antMatchers("/hello").access("hasRole('ROLE_ADMIN')")
            .antMatchers(   "/",
                            "/**",
                            "/user/activate",
                            "/user/activate/**",
                            "/user/create",
                            "/user/register",
                            "/webjars/**",
                            "/templates/**",
                            "/static/**",
                            "/favicon.ico"
            ).permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin().loginPage("/login").permitAll()
            .usernameParameter("username").passwordParameter("password")
            .and()
            .logout().permitAll()
            .and()
            .exceptionHandling().accessDeniedPage("/403")
            .and()
            .csrf().disable();


非常感谢您的帮助!

PS:我阅读了 Spring security ang Angular 教程,但我想使用前面描述的方法

编辑

我正在使用 Spring boot,而我的 application.properties 是:

spring.datasource.url = jdbc:mysql://localhost/betizy
spring.datasource.username =  root
spring.datasource.password =
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

这就是我的 Spring Security 配置的全部内容

【问题讨论】:

可能重复***.com/questions/41373326/… 我不明白为什么?我的问题是我需要一种方法来链接我的 UserController.java 和我在 SecurityConfig.java 中的方法。 @PostMaping 是一个解决方案吗? 我认为不是,这就是我认为它不是重复的原因。另外我不太了解他在链接主题中的问题。 【参考方案1】:

你可以使用 org.springframework.security.authentication.AuthenticationManager

@Autowired
private AuthenticationManager authenticationManager;

@RequestMapping(value="/login", method = RequestMethod.POST)
public JSONObject login(HttpServletRequest request, HttpServletResponse response, @RequestBody User user) 

    //does the authentication
    final Authentication authentication = authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(
                    user.getUsername(),
                    user.getPassword()
            )
    );
    SecurityContextHolder.getContext().setAuthentication(authentication);

    //just an example of return - you could easily just return the 200 code or smth
    return Json.createObjectBuilder()
            .add("firstName", user.getFirstName())
            .add("lastName", user.getLastName())
            .add("status", HttpStatus.OK);

希望对你有帮助。

【讨论】:

以上是关于手动 Spring 安全实现,通过角度和密码编码调用的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有密码编码的情况下使用 Spring 安全性?

如何使用 Rest 和 Spring 安全性通过 ldap 登录 Angular?

使用Spring Security为实时Grails应用程序增加BCrypt logrounds而不重新编码所有密码是否安全?

Spring Boot,使用编码密码实现登录

Spring 依赖注入的两种实现方式

Spring Security 5中的默认密码编码器