springboot 整合 springsecurity
导入jar包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
springsecurity的配置类(依赖于方法上加注解 进行权限验证)第一种 方法
@PreAuthorize("hasAuthority('/user/del')")
package com.liuchao.securitydemo.security.config; import com.liuchao.securitydemo.security.config.CustomUserDetailsService; import com.liuchao.securitydemo.security.entity.Menu; import com.liuchao.securitydemo.security.mapper.UserMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.BeanIds; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 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.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.List; @Component @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) //开启方法权限控制 @PreAuthorize("hasAuthority('/user/del')")在方法上加上这个可以验证权限 public class SecurityConfig extends WebSecurityConfigurerAdapter { @Resource private UserMapper userMapper; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception{ auth.userDetailsService(customUserDetailsService())//配置用户验证登录的类 .passwordEncoder(passwordEncoder());//这个是密码校验的类 } //配置校验的路径和不校验的路径 @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // 所有用户均可访问的资源 .antMatchers( "/favicon.ico","/css/**","/common/**","/js/**","/images/**","/captcha.jpg","/login","/userLogin","/login-error").permitAll() // 任何尚未匹配的URL只需要验证用户即可访问 .anyRequest().authenticated() .and() .formLogin().loginPage("/login").successForwardUrl("/index").failureForwardUrl("/login?error=1") .and() //权限拒绝的页面 .exceptionHandling().accessDeniedPage("/403"); http.logout().logoutSuccessUrl("/login"); /* List<Menu> allMenu = userMapper.findAllMenu(); ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry expressionInterceptUrlRegistry = http.authorizeRequests(); for(Menu menu:allMenu){ expressionInterceptUrlRegistry.antMatchers(menu.getUrl()).hasAnyAuthority(menu.getUrl()); } expressionInterceptUrlRegistry.antMatchers( "/favicon.ico","/css/**","/common/**","/js/**","/images/**","/captcha.jpg","/login","/userLogin","/login-error").permitAll() .anyRequest().authenticated() .and() .formLogin().loginPage("/login").successForwardUrl("/index").failureForwardUrl("/login?error=1") .and() .exceptionHandling().accessDeniedPage("/403");*/ } /** * 设置用户密码的加密方式 * @return */ @Bean public Md5PasswordEncoder passwordEncoder() {//密码校验器并注入spring return new Md5PasswordEncoder(); } /** * 自定义UserDetailsService,授权 * @return */ @Bean public CustomUserDetailsService customUserDetailsService(){//校验用户登录的类交注入spring return new CustomUserDetailsService(); } @Bean(name = BeanIds.AUTHENTICATION_MANAGER) @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } }
springsecurity的配置类(依赖于配置进行权限验证)第二种方法(可以不用依赖于方法上的注解 来进行权限验证)
package com.liuchao.securitydemo.security.config; import com.liuchao.securitydemo.security.config.CustomUserDetailsService; import com.liuchao.securitydemo.security.entity.Menu; import com.liuchao.securitydemo.security.mapper.UserMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.BeanIds; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 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.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.List; @Component @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) //开启方法权限控制 @PreAuthorize("hasAuthority('/user/del')")在方法上加上这个可以验证权限 public class SecurityConfig extends WebSecurityConfigurerAdapter { @Resource private UserMapper userMapper; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception{ auth.userDetailsService(customUserDetailsService()) .passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { /* http.authorizeRequests() // 所有用户均可访问的资源 .antMatchers( "/favicon.ico","/css/**","/common/**","/js/**","/images/**","/captcha.jpg","/login","/userLogin","/login-error").permitAll() // 任何尚未匹配的URL只需要验证用户即可访问 .anyRequest().authenticated() .and() .formLogin().loginPage("/login").successForwardUrl("/index").failureForwardUrl("/login?error=1") .and() //权限拒绝的页面 .exceptionHandling().accessDeniedPage("/403"); http.logout().logoutSuccessUrl("/login");*/ List<Menu> allMenu = userMapper.findAllMenu(); ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry expressionInterceptUrlRegistry = http.authorizeRequests(); for(Menu menu:allMenu){ expressionInterceptUrlRegistry.antMatchers(menu.getUrl()).hasAnyAuthority(menu.getUrl());//给每个地址进行授权只有有这个权限的才能访问 } expressionInterceptUrlRegistry.antMatchers( "/favicon.ico","/css/**","/common/**","/js/**","/images/**","/captcha.jpg","/login","/userLogin","/login-error").permitAll() .anyRequest().authenticated() .and() .formLogin().loginPage("/login").successForwardUrl("/index").failureForwardUrl("/login?error=1") .and() .exceptionHandling().accessDeniedPage("/403"); http.logout().logoutSuccessUrl("/login"); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { super.configure(auth); } /** * 设置用户密码的加密方式 * @return */ @Bean public Md5PasswordEncoder passwordEncoder() { return new Md5PasswordEncoder(); } /** * 自定义UserDetailsService,授权 * @return */ @Bean public CustomUserDetailsService customUserDetailsService(){ return new CustomUserDetailsService(); } @Bean(name = BeanIds.AUTHENTICATION_MANAGER) @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } }
验证用户登录的类
package com.liuchao.securitydemo.security.config; import com.liuchao.securitydemo.security.entity.Menu; import com.liuchao.securitydemo.security.entity.User; import com.liuchao.securitydemo.security.mapper.UserMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; 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; import org.springframework.util.StringUtils; import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; //@Component public class CustomUserDetailsService implements UserDetailsService { @Resource private UserMapper userMapper; @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { User user = userMapper.findByName(s); if(StringUtils.isEmpty(user)){ throw new UsernameNotFoundException("账号不存在"); } List<Menu> menuList = userMapper.findByUserId(user.getId()); List<GrantedAuthority> grantedAuthorities = new ArrayList<>(); for(Menu menu: menuList){ GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(menu.getUrl()); //此处将权限信息添加到 GrantedAuthority 对象中,在后面进行全权限验证时会使用GrantedAuthority 对象。 grantedAuthorities.add(grantedAuthority); } user.setAuthorities(grantedAuthorities);//给用户授权 return user; } }
用户的实体类必需要实现一个UserDetails类
package com.liuchao.securitydemo.security.entity; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import java.io.Serializable; import java.util.Collection; import java.util.Date; import java.util.List; public class User implements UserDetails,Serializable { private static final long serialVersionUID = -962358173215433342L; private Integer id; private String username; private String nickname; private String admin; private Date createDate; private String password; private List<? extends GrantedAuthority> authorities; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public void setUsername(String username) { this.username = username; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public String getAdmin() { return admin; } public void setAdmin(String admin) { this.admin = admin; } public Date getCreateDate() { return createDate; } public void setCreateDate(Date createDate) { this.createDate = createDate; } public void setPassword(String password) { this.password = password; } public void setAuthorities(List<? extends GrantedAuthority> authorities) { this.authorities = authorities; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } @Override public String getPassword() { return password; } @Override public String getUsername() { return username; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }
密码校验器
package com.liuchao.securitydemo.security.config; import org.springframework.security.crypto.password.PasswordEncoder; /** * 自定义密码比较器 3 * 在此 密码我就不加密了 */ public class Md5PasswordEncoder implements PasswordEncoder { @Override public String encode(CharSequence charSequence) { return charSequence.toString(); } @Override public boolean matches(CharSequence charSequence, String s) { return s.equals(charSequence); } }
springSecurity的获取用户 判断权限的一个工具类
package com.liuchao.securitydemo.security.util; import com.liuchao.securitydemo.security.entity.User; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.util.StringUtils; import java.util.Collection; public class SecurityUtils { public static Authentication getAuthentication() { return SecurityContextHolder.getContext().getAuthentication(); } public static Collection<? extends GrantedAuthority> getAllPermission(){ Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); return authorities; } //判断是否有权限 public static boolean hasPermission(String permission){ if(StringUtils.isEmpty(permission)){ return false; } Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); boolean hasPermission = false; for(GrantedAuthority grantedAuthority : authorities){ String authority = grantedAuthority.getAuthority(); if(authority.equals(permission)){ hasPermission =true; } } return hasPermission; } //或取当前登录的用户信息 public static User getUser() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); return (User) authentication.getPrincipal(); } public static void logout(){ SecurityContextHolder.clearContext(); } }
登录
package com.liuchao.securitydemo.security.controller;
import com.liuchao.securitydemo.security.entity.User;
import com.liuchao.securitydemo.security.exception.MyException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@Controller
public class LoginController {
@Autowired
private AuthenticationManager authenticationManager;
@RequestMapping("/login")
public String login(){
return "login.html";
}
@RequestMapping("/userLogin")
public String userLogin(@RequestParam("username")String userName,
@RequestParam("password")String password,
HttpServletRequest request) throws MyException {
if(StringUtils.isEmpty(userName)){
throw new MyException("没有输入用户名");
}
if(StringUtils.isEmpty(password)){
throw new MyException("没有输入密码");
}
User user=new User();
user.setUsername(userName);
user.setPassword(password);
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken=new UsernamePasswordAuthenticationToken(userName,password);
try{
//拦截走springsecurity的登录和授权
Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
SecurityContextHolder.getContext().setAuthentication(authenticate);
HttpSession session = request.getSession();
session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext()); // 这个非常重要,否则验证后将无法登陆
}catch (Exception e){
e.printStackTrace();
return "redirect:login-error?error=2";
}
return "redirect:index";
}
}
配置错误页面
@Configuration public class ErrorPageConfig implements ErrorPageRegistrar { private static final Logger logger = LoggerFactory.getLogger(ErrorPageConfig.class); @Override public void registerErrorPages(ErrorPageRegistry errorPageRegistry) { //1、按错误的类型显示错误的网页 // 错误类型为404,找不到网页的,默认显示404.html网页 ErrorPage e404 = new ErrorPage(HttpStatus.NOT_FOUND, "/404"); //错误类型为500,表示服务器响应错误,默认显示500.html网页 ErrorPage e500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/500"); ErrorPage e403 = new ErrorPage(HttpStatus.FORBIDDEN, "/403"); errorPageRegistry.addErrorPages(e404, e500,e403); } }
package com.liuchao.securitydemo.security.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class IndexController { @RequestMapping(value="/index") public String index() { return "index"; } @RequestMapping(value="/login-error") public String loginError(String error) { if("1".equals(error)){ return "login-error1"; } return "login-error2"; } @RequestMapping("/404") public String to404() { return "404"; } @RequestMapping("/403") public String to403() { return "403"; } @RequestMapping("/500") public String to500() { return "500"; } }
接口增删改查的实例页面
package com.liuchao.securitydemo.security.controller; import com.liuchao.securitydemo.security.entity.User; import com.liuchao.securitydemo.security.mapper.UserMapper; import com.liuchao.securitydemo.security.util.SecurityUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.util.HashMap; import java.util.List; @Controller @RequestMapping("/user") public class UserController { @Autowired private UserMapper userMapper; @RequestMapping(value = "/list") @PreAuthorize("hasAuthority('/user/list')") @ResponseBody public List login() { List<User> list = userMapper.getAllUsers(); return list; } @RequestMapping(value = "/update") @PreAuthorize("hasAuthority('/user/update')") @ResponseBody public HashMap<String, Object> update() { HashMap<String, Object> map = new HashMap<>(); map.put("state","success"); return map; } @RequestMapping(value = "/del") @PreAuthorize("hasAuthority('/user/del')") @ResponseBody public HashMap<String, Object> del() { HashMap<String, Object> map = new HashMap<>(); map.put("state","success"); return map; } @RequestMapping(value = "/add") @PreAuthorize("hasAuthority('/user/add')") @ResponseBody public HashMap<String, Object> add() { HashMap<String, Object> map = new HashMap<>(); map.put("state","success"); return map; } @RequestMapping(value = "/logout") public String logout() { SecurityUtils.logout(); return "redirect:login"; } @RequestMapping(value = "/info") @ResponseBody public User info() { return SecurityUtils.getUser(); } }