@qxr
Spring Security 是一个安全框架,前身是 Acegi Security , 能够为 Spring企业应用系统提供声明式的安全访问控制。
Spring Security 基于 Servlet 过滤器、 IoC和AOP , 为 Web 请求和方法调用提供身份确认和授权处理,避免了代码耦合,减少了大量重复代码工作。
Spring Security 提供了若干个可扩展的、可声明式使用的过滤器处理拦截的web请求。
在web请求处理时, Spring Security框架根据请求url和声明式配置,筛选出合适的一组过滤器集合拦截处理当前的web请求。
这些请求会被转给Spring Security的安全访问控制框架处理通过之后,请求再转发应用程序处理,从而增强了应用的安全性。
Spring Security 提供了可扩展的认证、鉴权机制对Web请求进行相应对处理。
认证:识别并构建用户对象,如:根据请求中的username,获取登录用户的详细信息,判断用户状态,缓存用户对象到请求上下文等。
决策:判断用户能否访问当前请求,如:识别请求url,根据用户、权限和资源(url)的对应关系,判断用户能否访问当前请求url。
####引入基本配置
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-securityartifactId>
dependency>
####修改端口
application.properties
server.port=8090
test.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>我是来测试的,您呢h1>
body>
html>
为了便于测试,把test.html页面放入项目,启动项目
首先我们测试一下localhost:8090/test.html
可以看到无论怎么输入都会进入到登录页面,我们用提供的user 和 密码登录
默认用户名为user
,密码为控制台打印的Using generated security password:...
登录后访问localhost:8090/test.html
体验完成,是不是很方便,但是它离我们的实际需求还差很远
首先 添加一个类 SecurityConfig
继承 WebSecurityConfigurerAdapter
@Configuration
@EnableWebSecurity
package com.czxy.config;
import com.czxy.service.UserService;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.DigestUtils;
/**
* @ClassName SecurityConfig
* @Author renxiuqin
* @Data 2019/1/5 16:44
*/
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Override
protected void configure(HttpSecurity http) throws Exception {
//表单登录,permitAll()表示这个不需要验证 登录页面,登录失败页面
http
.formLogin()
//登录页面
.loginPage("/login.html")
//登录提交路径
.loginProcessingUrl("/login/form").usernameParameter("username").passwordParameter("password").permitAll()
//登录失败跳转
.failureUrl("/login-error.html")
//登录完成后的跳转
.defaultSuccessUrl("/index.html")
.and()
.logout()
.logoutUrl("/logout")
//退出登录后的默认url
.logoutSuccessUrl("/login.html")
.and()
.authorizeRequests().anyRequest().authenticated()
.and()
.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(new PasswordEncoder() {
/**
* 功能描述:密码加密
* @param charSequence 明文
* @return String
*/
@Override
public String encode(CharSequence charSequence) {
return DigestUtils.md5DigestAsHex(charSequence.toString().getBytes());
}
/**
* 功能描述: 密码比较器
* @param charSequence 明文
* @param cipherText 密文
* @return boolean
*/
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(DigestUtils.md5DigestAsHex(charSequence.toString().getBytes()));
}
});
}
}
package com.czxy.domain;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import java.io.Serializable;
import java.util.Collection;
public class User implements Serializable, UserDetails {
private static final long serialVersionUID = 1L;
private String username;
private String password;
private String role;
private boolean accountNonExpired;
private boolean accountNonLocked;
private boolean credentialsNonExpired;
private boolean enabled;
public User(String username, String password, String role, boolean accountNonExpired, boolean accountNonLocked,
boolean credentialsNonExpired, boolean enabled) {
this.username = username;
this.password = password;
this.role = role;
this.accountNonExpired = accountNonExpired;
this.accountNonLocked = accountNonLocked;
this.credentialsNonExpired = credentialsNonExpired;
this.enabled = enabled;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return AuthorityUtils.commaSeparatedStringToAuthorityList(role);
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return accountNonExpired;
}
@Override
public boolean isAccountNonLocked() {
return accountNonLocked;
}
@Override
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
@Override
public boolean isEnabled() {
return enabled;
}
}
继承了UserDetailsService
package com.czxy.service;
import com.czxy.domain.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
/**
*
* 功能描述: 模拟数据库数据
*
* @param:
* @return:
*/
@Component
public class UserService implements UserDetailsService {
/**
*
* 功能描述:根据用户名查询数据库判断用户名是否存在
*
* @param: username
* @return: UserInfo
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if ("admin".equals(username)) {
User user = new User("admin", "e10adc3949ba59abbe56e057f20f883e", "ROLE_ADMIN", true, true, true, true);
return user;
}
return null;
}
}
package com.czxy.service;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import java.util.Set;
/**
* @ClassName RbacService
* @Author renxiuqin
* @Data 2019/1/5 16:59
*/
@Component("rbacService")
public class RbacService {
private AntPathMatcher antPathMatcher = new AntPathMatcher();
public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
Object principal = authentication.getPrincipal();
boolean hasPermission = false;
//首先判断先当前用户是否是我们 UserDetails 对象。
if (principal instanceof UserDetails) {
String userName = ((UserDetails) principal).getUsername();
// 数据库读取 读取 用户 所拥有权限的所有 URL
Set<String> urls = new HashSet<>();
urls.add("/hello");
for (String url : urls) {
if (antPathMatcher.match(url, request.getRequestURI())) {
hasPermission = true;
break;
}
}
}
return hasPermission;
}
}
在SecurityConfig.java中添加控制
.and()
.authorizeRequests()
.anyRequest().access("@rbacService.hasPermission(request,authentication)")
package com.czxy.controller;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@RequestMapping("/hello")
public String helloWorld() {
return "Hello , My name is spring security !!!";
}
@RequestMapping("/userInfo")
public Object whoIm() {
return SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}