Spring Security致力于为Java应用提供认证和授权管理。它是一个强大的,高度自定义的认证和访问控制框架。具体介绍参见https://docs.spring.io/spring-security/site/docs/5.0.5.RELEASE/reference/htmlsingle/
这句话包括两个关键词:Authentication(认证)和 Authorization(授权)。认证是验证用户身份的合法性,而授权是控制你可以做什么。
代码地址:https://github.com/zhangpu1211/Spring-Security-Demos
初体验
创建springboot项目,添加web,spring security依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
添加一个hello controller,当未添加spring security的时候,项目运行后,可以直接通过http://localhost:8080/访问该接口,但是添加spring security之后,首先就需要Authentication,即认证。
@RestController
public class Hello {
@GetMapping("/hello")
public String hello(){
return "hello";
}
}

此时系统使用默认配置,即用户名为user,密码随机生成在控制台中。使用用户名、密码登录之后,可以访问系统内部资源。

手工设置用户名密码
配置文件配置
配置用户名为admin,密码123,角色为admin,注意此时使用的是yml文件格式
spring:
security:
user:
name: admin
password: 123
roles: ['admin']
Java代码实现
- 创建SecurityConfig类
SecurityConfig继承自WebSecurityConfigurerAdapter,通过名字就可以发现这是一个Security配置器。 - 继承拥有AuthenticationManagerBuilder的configure方法
这里要注意:首先类上要加@Configuration
注解,此外要配置密码加密函数
package org.zp.secret.config;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
//配置注解
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//密码加密函数
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
//password为BCryptPasswordEncoder加密123后的值
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("$2a$10$2cPRItUHyE1GSZnrYWHiQevpbxn4ikWgOa1PYL5miWvqK8GFVCWb6").roles("admin")
.and().withUser("java").password("$2a$10$rygGQylvmoAFmPcKQP6xvepNVAw9Bxp0sbAphxKQwhAV79Au0ECvq").roles("user");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasAnyRole("admin","user")
.anyRequest().authenticated() //其他路径认证之后就可以访问
.and()
.formLogin()
.loginProcessingUrl("/doLogin") //处理登录请求的地址
.permitAll()
.and()
.csrf().disable();
}
}
登录成功与失败之处理
针对前端采用框架不同可以采用不同的处理方式,均在configure(HttpSecurity http)
方法中进行配置。
- 前后端不分,使用
successForwardUrl
返回重定向的地址 - 前后端分离,使用
successHandler
,重写onAuthenticationSuccess
方法
package org.zp.secret.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import org.zp.secret.utils.RespBean;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component
public class MyAuthenctiationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication auth) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
RespBean ok = RespBean.ok("登录成功!");
String s = new ObjectMapper().writeValueAsString(ok);
out.write(s);
out.flush();
out.close();
}
}
网友评论