Spring Security安全框架初识
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/**");
}
}
- 点赞
- 收藏
- 关注作者
评论(0)