Spring Security-整合Spring Boot(原始
2022-05-17 本文已影响0人
石头耳东
零、本文纲要
一、快速入门
二、使用内存数据认证
三、连接数据库认证
四、授权管理
一、快速入门
1. 基础依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
2. 配置文件application.yml
server:
port: 8080
3. 启动类
@SpringBootApplication
public class SpringSecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SpringSecurityApplication.class, args);
}
}
4. 表现层
@Controller
@RequestMapping("/product")
public class ProductController {
@RequestMapping
@ResponseBody
public String findAll(){
return "success";
}
}
5. 测试
此时会跳出Spring Security默认的登录页面。
默认账户:user
默认密码:Using generated security password: 649253a1-3773-4c05-a480-1c08343928f2
注意:密码需要在启动后的控制台输出日志处查找。
二、使用内存数据认证
1. 添加整合JSP的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
2. 编写Security配置文件
@Configuration
@EnableWebSecurity
public class SecurityConfig {...}
- ① @EnableWebSecurity注解
@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import({ WebSecurityConfiguration.class,
SpringWebMvcImportSelector.class,
OAuth2ImportSelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
boolean debug() default false;
}
在该注解的源码上方,官方提供了一个基础的配置类,具体如下:
@Configuration
@EnableWebSecurity
public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
// Spring Security should completely ignore URLs starting with /resources/
.antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/public/**").permitAll().anyRequest()
.hasRole("USER").and()
// Possibly more configuration ...
.formLogin() // enable form based log in
// set permitAll for all URLs associated with Form Login
.permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
// enable in memory based authentication with a user named "user" and "admin"
.inMemoryAuthentication().withUser("user").password("password").roles("USER")
.and().withUser("admin").password("password").roles("USER", "ADMIN");
}
// Possibly more overridden methods ...
}
- ② 编写自己的配置类
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//认证用户的来源【内存 或者 数据库】
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
//此种写法是来自内存,来自数据库后面优化会提到
auth.inMemoryAuthentication()
.withUser("user").password("{noop}123456").roles("USER")
.and()
.withUser("admin").password("{noop}123456").roles("USER", "ADMIN");
}
//配置Spring Security的相关信息
@Override
public void configure(HttpSecurity http) throws Exception {
//释放静态资源,指定资源拦截规则,指定自定义认证页面,指定退出认证配置,csrf配置
http.authorizeRequests()
.antMatchers("/login.jsp", "/failer.jsp", "/css/**", "/img/**", "/plugins/**").permitAll() //释放静态资源
.antMatchers("/**").hasAnyRole("USER", "ADMIN") //拦截所有请求,需要"USER", "ADMIN"认证
.anyRequest().authenticated() //其他请求需要认证通过才能访问
.and()
.formLogin() //配置自定义认证页面
.loginPage("/login.jsp")
.loginProcessingUrl("/login")
.successForwardUrl("/index.jsp")
.failureForwardUrl("/failer.jsp")
.permitAll()
.and()
.logout() //配置退出认证
.logoutUrl("/logout")
.logoutSuccessUrl("/login.jsp")
.invalidateHttpSession(true)
.permitAll()
.and()
.csrf().disable(); //csrf配置
}
}
3. 测试
通过Execute Maven Goal执行指令启动:spring-boot:run
三、连接数据库认证
1. 添加持久层所需依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--通用Mapper-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
2. 编写配置
在application.yml处添加配置
server:
port: 8080
spring:
mvc:
view:
prefix: /pages/
suffix: .jsp
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///security_authority?serverTimezone=UTC
username: root
password: 123456
mybatis:
type-aliases-package: com.stone.domain
configuration:
map-underscore-to-camel-case: true
logging:
level:
com.stone: debug
3. 编写实体类
- ① SysRole实现GrantedAuthority接口
public class SysRole implements GrantedAuthority {
private Integer id;
private String roleName;
private String roleDesc;
@JsonIgnore //此方法是实现规范的方法,并不是当前对象原有属性
@Override
public String getAuthority() {
return roleName;
}
//省略了Get和Set方法
}
- ② SysUser实现UserDetails接口
public class SysUser implements UserDetails {
private Integer id;
private String username;
private String password;
private Integer status;
private List<SysRole> roles;
//省略了Get和Set方法
//省略了重写方法
}
注意:在实体类重写的方法上添加@JsonIgnore注解
自定义的SysUser类直接实现UserDetails接口带来的好处:可以省去使用时的手动转换。
4. 编写Mapper类
- ① SysRole的Mapper类
public interface RoleMapper extends Mapper<SysRole> {
@Select("select r.id, r.role_name roleName, r.role_desc roleDesc " +
"from sys_role r, sys_user_role ur " +
"where r.id = ur.rid and ur.uid = #{uid}")
public List<SysRole> findById(Integer uid);
}
- ② SysUser的Mapper类
public interface UserMapper extends Mapper<SysUser> {
@Select("select * from sys_user where username = #{username}")
@Results({
@Result(id = true, property = "id", column = "id"),
@Result(property = "roles", column = "id", javaType = List.class,
many = @Many(select = "com.stone.mapper.RoleMapper.findById"))
})
public SysUser findByName(String username);
}
5. 编写service接口及实现类
- ① service接口
此处我们的接口需要继承UserDetailsService接口
public interface UserService extends UserDetailsService {
}
- ② service实现类
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userMapper.findByName(username);
}
}
6. 修改认证对象来源
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
//认证用户的来源【数据库】
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
//注意:configure方便不变,此处省略
}
7. 测试
四、授权管理
1. @EnableGlobalMethodSecurity
此处可以参考Spring Security-原始篇(XML配置版)功能优化篇中权限管理-注解说明的介绍。
@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import({ GlobalMethodSecuritySelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableGlobalMethodSecurity {
boolean prePostEnabled() default false;
boolean securedEnabled() default false;
boolean jsr250Enabled() default false;
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
2. 添加授权
- ① 开启授权注解支持
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true) //开启SpringSecurity注解支持
public class SecurityConfig extends WebSecurityConfigurerAdapter {...}
- ② 在实现类方法上添加授权注解
@Service
public class ProductServiceImpl implements ProductService {
@Secured({"ROLE_ADMIN","ROLE_PRODUCT"})
@Override
public String findAll() {
return "product-list";
}
}
3. 统一异常处理
@ControllerAdvice
public class HandlerControllerException {
@ExceptionHandler(AccessDeniedException.class)
public String handleAccessDeniedException(){
return "redirect:/403.jsp";
}
@ExceptionHandler(Throwable.class)
public String handleThrowable(){
return "redirect:/500.jsp";
}
}
4. 测试
五、结尾
以上即为Spring Security-整合Spring Boot(原始篇-单体架构)的基础内容,感谢阅读。