Spring Security安全框架初识

举报
多米诺的古牌 发表于 2022/07/18 23:20:27 2022/07/18
【摘要】 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。

1、简介   

    Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。框架中主要涉及两个操作,一个是认证,从名字就可以

知道,是为获得一个标识,确认哪些用户可以访问,哪些用户会被拦截;还有一个是授权,从名字中也很容易明白,授权就是赋予一定的权利,可以去做某一些操

作,而在授权之前,框架中首先会判断是否是认证的用户,这就是Spring Security安全框架中认证和授权相互配合的操作,用这样的操作来保证系统的安全可靠。

2、Spring Security默认登录页面

    在创建一个Spring Security安全框架后,会默认带一个登录页面,创建的过程也很简单,只要需要创建web项目的时候引入Spring Security的相关依赖就可以完成创建了。

        <!--springsecurity 主要依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
        </dependency>

    在创建好后会有一个默认的登录页面,默认配置用户为user,密码会输出在控制台上,那么问题来了我们什么都没有写,这个登录页面是哪里来的呢?而且还自带账号和密码。

     其实这个登录页面是一个默认filter里面直接写入response的,可以在自定义实现的 WebSecurityConfigurerAdapter 中有找到这么一个方法,再在其中找到一个 默认配置

DefaultLoginPageConfigurer。它会添加两个默认filter,再点进去,其中的loginPageGeneratingFilter中,就会生成登录页面是怎么写的了。

private void applyDefaultConfiguration(HttpSecurity http) throws Exception {
		http.csrf();
		http.addFilter(new WebAsyncManagerIntegrationFilter());
		http.exceptionHandling();
		http.headers();
		http.sessionManagement();
		http.securityContext();
		http.requestCache();
		http.anonymous();
		http.servletApi();
		http.apply(new DefaultLoginPageConfigurer<>());
		http.logout();
	}
	public void configure(H http) {
		AuthenticationEntryPoint authenticationEntryPoint = null;
		ExceptionHandlingConfigurer<?> exceptionConf = http.getConfigurer(ExceptionHandlingConfigurer.class);
		if (exceptionConf != null) {
			authenticationEntryPoint = exceptionConf.getAuthenticationEntryPoint();
		}
		if (this.loginPageGeneratingFilter.isEnabled() && authenticationEntryPoint == null) {
			this.loginPageGeneratingFilter = postProcess(this.loginPageGeneratingFilter);
			http.addFilter(this.loginPageGeneratingFilter);
			http.addFilter(this.logoutPageGeneratingFilter);
		}
	}
private String generateLoginPageHtml(HttpServletRequest request, boolean loginError, boolean logoutSuccess) {
		String errorMsg = "Invalid credentials";
		if (loginError) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				AuthenticationException ex = (AuthenticationException) session
						.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
				errorMsg = (ex != null) ? ex.getMessage() : "Invalid credentials";
			}
		}
		String contextPath = request.getContextPath();
		StringBuilder sb = new StringBuilder();
		sb.append("<!DOCTYPE html>\n");
		sb.append("<html lang=\"en\">\n");
		sb.append("  <head>\n");
		sb.append("    <meta charset=\"utf-8\">\n");
		sb.append("    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n");
		sb.append("    <meta name=\"description\" content=\"\">\n");
		sb.append("    <meta name=\"author\" content=\"\">\n");
		sb.append("    <title>Please sign in</title>\n");
		sb.append("    <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" "
				+ "rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n");
		sb.append("    <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" "
				+ "rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n");
		sb.append("  </head>\n");
		sb.append("  <body>\n");
		sb.append("     <div class=\"container\">\n");
		if (this.formLoginEnabled) {
			sb.append("      <form class=\"form-signin\" method=\"post\" action=\"" + contextPath
					+ this.authenticationUrl + "\">\n");
			sb.append("        <h2 class=\"form-signin-heading\">Please sign in</h2>\n");
			sb.append(createError(loginError, errorMsg) + createLogoutSuccess(logoutSuccess) + "        <p>\n");
			sb.append("          <label for=\"username\" class=\"sr-only\">Username</label>\n");
			sb.append("          <input type=\"text\" id=\"username\" name=\"" + this.usernameParameter
					+ "\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n");
			sb.append("        </p>\n");
			sb.append("        <p>\n");
			sb.append("          <label for=\"password\" class=\"sr-only\">Password</label>\n");
			sb.append("          <input type=\"password\" id=\"password\" name=\"" + this.passwordParameter
					+ "\" class=\"form-control\" placeholder=\"Password\" required>\n");
			sb.append("        </p>\n");
			sb.append(createRememberMe(this.rememberMeParameter) + renderHiddenInputs(request));
			sb.append("        <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n");
			sb.append("      </form>\n");
		}
		if (this.openIdEnabled) {
			sb.append("      <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"" + contextPath
					+ this.openIDauthenticationUrl + "\">\n");
			sb.append("        <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\n");
			sb.append(createError(loginError, errorMsg) + createLogoutSuccess(logoutSuccess) + "        <p>\n");
			sb.append("          <label for=\"username\" class=\"sr-only\">Identity</label>\n");
			sb.append("          <input type=\"text\" id=\"username\" name=\"" + this.openIDusernameParameter
					+ "\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n");
			sb.append("        </p>\n");
			sb.append(createRememberMe(this.openIDrememberMeParameter) + renderHiddenInputs(request));
			sb.append("        <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n");
			sb.append("      </form>\n");
		}
		if (this.oauth2LoginEnabled) {
			sb.append("<h2 class=\"form-signin-heading\">Login with OAuth 2.0</h2>");
			sb.append(createError(loginError, errorMsg));
			sb.append(createLogoutSuccess(logoutSuccess));
			sb.append("<table class=\"table table-striped\">\n");
			for (Map.Entry<String, String> clientAuthenticationUrlToClientName : this.oauth2AuthenticationUrlToClientName
					.entrySet()) {
				sb.append(" <tr><td>");
				String url = clientAuthenticationUrlToClientName.getKey();
				sb.append("<a href=\"").append(contextPath).append(url).append("\">");
				String clientName = HtmlUtils.htmlEscape(clientAuthenticationUrlToClientName.getValue());
				sb.append(clientName);
				sb.append("</a>");
				sb.append("</td></tr>\n");
			}
			sb.append("</table>\n");
		}
		if (this.saml2LoginEnabled) {
			sb.append("<h2 class=\"form-signin-heading\">Login with SAML 2.0</h2>");
			sb.append(createError(loginError, errorMsg));
			sb.append(createLogoutSuccess(logoutSuccess));
			sb.append("<table class=\"table table-striped\">\n");
			for (Map.Entry<String, String> relyingPartyUrlToName : this.saml2AuthenticationUrlToProviderName
					.entrySet()) {
				sb.append(" <tr><td>");
				String url = relyingPartyUrlToName.getKey();
				sb.append("<a href=\"").append(contextPath).append(url).append("\">");
				String partyName = HtmlUtils.htmlEscape(relyingPartyUrlToName.getValue());
				sb.append(partyName);
				sb.append("</a>");
				sb.append("</td></tr>\n");
			}
			sb.append("</table>\n");
		}
		sb.append("</div>\n");
		sb.append("</body></html>");
		return sb.toString();
	}

这种直接拼接的写法很简单粗暴,虽然不是很优雅但是不会引入别的东西,只用原生的方法拼接,极大的减少了冲突等等一系列问题的产生。

这样我们知道了登录页面是怎么来的了。但是这个账号和密码又是怎么来的呢?

可以在自己的依赖包中找到相关的Properties的配置

F:\maven\org\springframework\boot\spring-boot-autoconfigure\2.6.7\spring-boot-autoconfigure-

2.6.7.jar!\org\springframework\boot\autoconfigure\security\SecurityProperties.class

当然从上面的properties中我们可以看出这是,框架默认的配置,我们是可以对其进行修改的。

只需要在yml配置文件中配置用户名和密码就可以完成spring security登录页面的账号和密码配置了。当然再配置类中也可以进行配置。

spring:
  security:
    user:
      name: test
      password: 123456

也可以通过配置类完成很多其他设置如下,其中@Configuration 注解Bean 放到容器中管理,@EnableWebSecurity注解 用于将Security 生成 Bean,一定记得要加

上才能使配置类生效。

package com.test.config;

import com.test.service.MyUserService;
import org.springframework.beans.factory.annotation.Autowired;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * @author 
 * @date 
 */
@Configuration     // 将Bean 放到容器中管理
@EnableWebSecurity // 用于将Security 生成 Bean
public class SpringSecurityConfig  extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserService myUserService;
    /*
     * 接口请求拦截
     **/
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()  //安全请求策略
                .antMatchers("/home").permitAll() //可放行请求配置
                .anyRequest().authenticated()    //其他请求进行拦截
                .and()
                .logout().permitAll()  // 注销任意访问
                .and()
                .formLogin();
        http.cors().disable();
    }
    /*
     *  告诉程序,系统中有个用户 用户名为 admin ,密码为 admin  角色为 ADMIN
     * */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //可以设置内存指定的登录的账号密码,指定角色
        //不加.passwordEncoder(new MyPasswordEncoder())或者注入该类的Bean
        //就不是以明文的方式进行匹配,会报错
        auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
        auth.inMemoryAuthentication().withUser("demo").password("demo").roles("ADMIN");
        auth.inMemoryAuthentication().withUser("testRole").password("testRole").roles("AD");
        auth.userDetailsService(myUserService).passwordEncoder(new MyPasswordEncoder());

    }
    /*
     *  前端拦截
     * */
    @Override
    public void configure(WebSecurity web){
        // 忽视 js 、css 、 images 后缀访问
        web.ignoring().antMatchers("/js/**","/css/**","/images/**");
    }
}





【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。