项目GitHub地址 :
https://github.com/FrameReserve/TrainingBoot
Spring Boot (三)集成spring security,标记地址:
https://github.com/FrameReserve/TrainingBoot/releases/tag/0.0.3
pom.xml
只列举 Spring Security配置,完整配置请查看Git项目地址
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
- <java.version>1.8</java.version>
-
- <mybatis.version>3.4.1</mybatis.version>
- <mybatis.spring.version>1.3.0</mybatis.spring.version>
-
- <spring-security.version>4.1.0.RELEASE</spring-security.version>
- </properties>
-
-
-
-
- <dependency>
- <groupId>org.springframework.security</groupId>
- <artifactId>spring-security-web</artifactId>
- <version>${spring-security.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.security</groupId>
- <artifactId>spring-security-config</artifactId>
- <version>${spring-security.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.security</groupId>
- <artifactId>spring-security-taglibs</artifactId>
- <version>${spring-security.version}</version>
- </dependency>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <!-- 依赖版本 --> <mybatis.version>3.4.1</mybatis.version> <mybatis.spring.version>1.3.0</mybatis.spring.version> <spring-security.version>4.1.0.RELEASE</spring-security.version> </properties><!-- spring security --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${spring-security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${spring-security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>${spring-security.version}</version> </dependency>
Spring Security 配置类:
src/main/java/com/training/core/security/WebSecurityConfig.java
package com.training.core.security;import java.util.ArrayList;import java.util.List;import javax.annotation.Resource;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.access.AccessDecisionManager;import org.springframework.security.access.AccessDecisionVoter;import org.springframework.security.access.vote.AuthenticatedVoter;import org.springframework.security.access.vote.RoleVoter;import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.authentication.event.LoggerListener;import org.springframework.security.config.annotation.ObjectPostProcessor;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.core.userdetails.UserDetailsService;import org.springframework.security.web.access.AccessDeniedHandler;import org.springframework.security.web.access.AccessDeniedHandlerImpl;import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;import org.springframework.security.web.access.expression.WebExpressionVoter;import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;import org.springframework.security.web.util.matcher.AntPathRequestMatcher;import com.training.sysmanager.service.AclResourcesService;import com.training.sysmanager.service.impl.AclResourcesServiceImpl;/** * Created by Athos on 2016-10-16. */@Configuration@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled = true)public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Resource private UserDetailsService userDetailsService; @Resource private MySecurityMetadataSource mySecurityMetadataSource; @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterAfter(MyUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); // 开启默认登录页面 http.authorizeRequests().anyRequest().authenticated().withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() { public <O extends FilterSecurityInterceptor> O postProcess(O fsi) { fsi.setSecurityMetadataSource(mySecurityMetadataSource); fsi.setAccessDecisionManager(accessDecisionManager()); fsi.setAuthenticationManager(authenticationManagerBean()); return fsi; } }).and().exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login.html")).and().logout().logoutSuccessUrl("/index.html").permitAll(); // 自定义accessDecisionManager访问控制器,并开启表达式语言 http.exceptionHandling().accessDeniedHandler(accessDeniedHandler()).and().authorizeRequests().anyRequest().authenticated().expressionHandler(webSecurityExpressionHandler()); // 自定义登录页面 http.csrf().disable(); // 自定义注销 // http.logout().logoutUrl("/logout").logoutSuccessUrl("/login") // .invalidateHttpSession(true); // session管理 http.sessionManagement().maximumSessions(1); // RemeberMe // http.rememberMe().key("webmvc#FD637E6D9C0F1A5A67082AF56CE32485"); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 自定义UserDetailsService auth.userDetailsService(userDetailsService); } @Bean UsernamePasswordAuthenticationFilter MyUsernamePasswordAuthenticationFilter() { UsernamePasswordAuthenticationFilter myUsernamePasswordAuthenticationFilter = new UsernamePasswordAuthenticationFilter(); myUsernamePasswordAuthenticationFilter.setPostOnly(true); myUsernamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManagerBean()); myUsernamePasswordAuthenticationFilter.setUsernameParameter("name_key"); myUsernamePasswordAuthenticationFilter.setPasswordParameter("pwd_key"); myUsernamePasswordAuthenticationFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST")); myUsernamePasswordAuthenticationFilter.setAuthenticationFailureHandler(simpleUrlAuthenticationFailureHandler()); return myUsernamePasswordAuthenticationFilter; } @Bean AccessDeniedHandler accessDeniedHandler() { AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl(); accessDeniedHandler.setErrorPage("/securityException/accessDenied"); return accessDeniedHandler; } @Bean public LoggerListener loggerListener() { System.out.println("org.springframework.security.authentication.event.LoggerListener"); return new LoggerListener(); } @Bean public org.springframework.security.access.event.LoggerListener eventLoggerListener() { System.out.println("org.springframework.security.access.event.LoggerListener"); return new org.springframework.security.access.event.LoggerListener(); } /* * * 这里可以增加自定义的投票器 */ @Bean(name = "accessDecisionManager") public AccessDecisionManager accessDecisionManager() { List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList(); decisionVoters.add(new RoleVoter()); decisionVoters.add(new AuthenticatedVoter()); decisionVoters.add(webExpressionVoter());// 启用表达式投票器 MyAccessDecisionManager accessDecisionManager = new MyAccessDecisionManager(decisionVoters); return accessDecisionManager; } @Bean(name = "authenticationManager") @Override public AuthenticationManager authenticationManagerBean() { AuthenticationManager authenticationManager = null; try { authenticationManager = super.authenticationManagerBean(); } catch (Exception e) { e.printStackTrace(); } return authenticationManager; } @Bean(name = "failureHandler") public SimpleUrlAuthenticationFailureHandler simpleUrlAuthenticationFailureHandler() { return new SimpleUrlAuthenticationFailureHandler("/getLoginError"); } @Bean(name = "aclResourcesService") @ConditionalOnMissingBean public AclResourcesService aclResourcesService() { return new AclResourcesServiceImpl(); } /* * 表达式控制器 */ @Bean(name = "expressionHandler") public DefaultWebSecurityExpressionHandler webSecurityExpressionHandler() { DefaultWebSecurityExpressionHandler webSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler(); return webSecurityExpressionHandler; } /* * 表达式投票器 */ @Bean(name = "expressionVoter") public WebExpressionVoter webExpressionVoter() { WebExpressionVoter webExpressionVoter = new WebExpressionVoter(); webExpressionVoter.setExpressionHandler(webSecurityExpressionHandler()); return webExpressionVoter; }}
自定义 UserDetailsService 用户、角色、资源获取类:
src/main/java/com/training/core/security/UserDetailsServiceImpl.java
- package com.training.core.security;
-
- import java.util.ArrayList;
- import java.util.List;
-
- import javax.annotation.Resource;
-
- import org.springframework.security.core.GrantedAuthority;
- import org.springframework.security.core.authority.SimpleGrantedAuthority;
- import org.springframework.security.core.userdetails.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.Service;
-
- import com.training.sysmanager.entity.AclResources;
- import com.training.sysmanager.entity.AclUser;
- import com.training.sysmanager.service.AclResourcesService;
- import com.training.sysmanager.service.AclRoleResourcesService;
- import com.training.sysmanager.service.AclUserService;
-
-
-
-
- @Service("userDetailsService")
- public class UserDetailsServiceImpl implements UserDetailsService {
-
- @Resource
- private AclUserService aclUserService;
- @Resource
- private AclRoleResourcesService aclRoleResourcesService;
- @Resource
- private AclResourcesService aclResourcesService;
-
-
-
-
- @Override
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
- List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
- AclUser aclUser = aclUserService.findAclUserByName(username);
- String resourceIds = aclRoleResourcesService.selectResourceIdsByRoleIds(aclUser.getRoleIds());
- List<AclResources> aclResourcesList = aclResourcesService.selectAclResourcesByResourceIds(resourceIds);
- for (AclResources aclResources : aclResourcesList) {
- auths.add(new SimpleGrantedAuthority(aclResources.getAuthority().toUpperCase()));
- }
-
- return new User(aclUser.getUserName().toLowerCase(),aclUser.getUserPwd().toLowerCase(),true,true,true,true,auths);
- }
- }
package com.training.core.security;import java.util.ArrayList;import java.util.List;import javax.annotation.Resource;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.authority.SimpleGrantedAuthority;import org.springframework.security.core.userdetails.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.Service;import com.training.sysmanager.entity.AclResources;import com.training.sysmanager.entity.AclUser;import com.training.sysmanager.service.AclResourcesService;import com.training.sysmanager.service.AclRoleResourcesService;import com.training.sysmanager.service.AclUserService;/** * Created by Athos on 2016-10-16. */@Service("userDetailsService")public class UserDetailsServiceImpl implements UserDetailsService { @Resource private AclUserService aclUserService; @Resource private AclRoleResourcesService aclRoleResourcesService; @Resource private AclResourcesService aclResourcesService; /* (non-Javadoc) * @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String) */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>(); AclUser aclUser = aclUserService.findAclUserByName(username); String resourceIds = aclRoleResourcesService.selectResourceIdsByRoleIds(aclUser.getRoleIds()); List<AclResources> aclResourcesList = aclResourcesService.selectAclResourcesByResourceIds(resourceIds); for (AclResources aclResources : aclResourcesList) { auths.add(new SimpleGrantedAuthority(aclResources.getAuthority().toUpperCase())); }// auths.addAll(aclResourcesList.stream().map(resources -> new SimpleGrantedAuthority(resources.getAuthority().toUpperCase())).collect(Collectors.toList())); return new User(aclUser.getUserName().toLowerCase(),aclUser.getUserPwd().toLowerCase(),true,true,true,true,auths); }}
自定义securityMetadataSource:
src/main/java/com/training/core/security/MySecurityMetadataSource.java
- package com.training.core.security;
-
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
-
- import javax.servlet.http.HttpServletRequest;
-
- import org.springframework.security.access.ConfigAttribute;
- import org.springframework.security.access.SecurityConfig;
- import org.springframework.security.web.FilterInvocation;
- import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
- import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
- import org.springframework.security.web.util.matcher.RequestMatcher;
- import org.springframework.stereotype.Component;
-
- import com.training.sysmanager.entity.AclResources;
- import com.training.sysmanager.service.AclResourcesService;
-
-
-
-
- @Component("mySecurityMetadataSource")
- public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
-
- private static Map<String,Collection<ConfigAttribute>> aclResourceMap = null;
- private AclResourcesService aclResourcesService;
-
-
-
-
-
- public MySecurityMetadataSource(AclResourcesService aclResourcesService){
- this.aclResourcesService=aclResourcesService;
- loadResourceDefine();
- }
-
- @Override
- public Collection<ConfigAttribute> getAttributes(Object object)throws IllegalArgumentException{
- HttpServletRequest request=((FilterInvocation)object).getRequest();
- Iterator<String> ite = aclResourceMap.keySet().iterator();
- while (ite.hasNext()){
- String resURL = ite.next();
- RequestMatcher requestMatcher = new AntPathRequestMatcher(resURL);
- if(requestMatcher.matches(request)){
- return aclResourceMap.get(resURL);
- }
- }
- return null;
- }
-
- @Override
- public Collection<ConfigAttribute> getAllConfigAttributes() {
- System.out.println("metadata : getAllConfigAttributes");
- return null;
- }
-
- @Override
- public boolean supports(Class<?> clazz) {
- System.out.println("metadata : supports");
- return true;
- }
-
-
- private void loadResourceDefine(){
-
-
-
- List<AclResources> aclResourceses = aclResourcesService.selectAclResourcesTypeOfRequest();
- aclResourceMap = new HashMap<>();
- for (AclResources aclResources:aclResourceses){
- ConfigAttribute ca = new SecurityConfig(aclResources.getAuthority().toUpperCase());
- String url = aclResources.getUrl();
- if(aclResourceMap.containsKey(url)){
- Collection<ConfigAttribute> value = aclResourceMap.get(url);
- value.add(ca);
- aclResourceMap.put(url,value);
-
- }else {
- Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
- atts.add(ca);
- aclResourceMap.put(url,atts);
- }
- }
- }
- }
package com.training.core.security;import java.util.ArrayList;import java.util.Collection;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.springframework.security.access.ConfigAttribute;import org.springframework.security.access.SecurityConfig;import org.springframework.security.web.FilterInvocation;import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;import org.springframework.security.web.util.matcher.AntPathRequestMatcher;import org.springframework.security.web.util.matcher.RequestMatcher;import org.springframework.stereotype.Component;import com.training.sysmanager.entity.AclResources;import com.training.sysmanager.service.AclResourcesService;/** * Created by Athos on 2016-10-16. */@Component("mySecurityMetadataSource")public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource { private static Map<String,Collection<ConfigAttribute>> aclResourceMap = null; private AclResourcesService aclResourcesService; /** * 构造方法 */ //1 public MySecurityMetadataSource(AclResourcesService aclResourcesService){ this.aclResourcesService=aclResourcesService; loadResourceDefine(); } @Override public Collection<ConfigAttribute> getAttributes(Object object)throws IllegalArgumentException{ HttpServletRequest request=((FilterInvocation)object).getRequest(); Iterator<String> ite = aclResourceMap.keySet().iterator(); while (ite.hasNext()){ String resURL = ite.next(); RequestMatcher requestMatcher = new AntPathRequestMatcher(resURL); if(requestMatcher.matches(request)){ return aclResourceMap.get(resURL); } } return null; } //4 @Override public Collection<ConfigAttribute> getAllConfigAttributes() { System.out.println("metadata : getAllConfigAttributes"); return null; } //3 @Override public boolean supports(Class<?> clazz) { System.out.println("metadata : supports"); return true; } private void loadResourceDefine(){ /** * 因为只有权限控制的资源才需要被拦截验证,所以只加载有权限控制的资源 */ List<AclResources> aclResourceses = aclResourcesService.selectAclResourcesTypeOfRequest(); aclResourceMap = new HashMap<>(); for (AclResources aclResources:aclResourceses){ ConfigAttribute ca = new SecurityConfig(aclResources.getAuthority().toUpperCase()); String url = aclResources.getUrl(); if(aclResourceMap.containsKey(url)){ Collection<ConfigAttribute> value = aclResourceMap.get(url); value.add(ca); aclResourceMap.put(url,value); }else { Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>(); atts.add(ca); aclResourceMap.put(url,atts); } } }}
自定义AbstractAccessDecisionManager权限决策类,
src/main/java/com/training/core/security/MyAccessDecisionManager.java
- package com.training.core.security;
-
- import org.springframework.security.access.AccessDecisionVoter;
- import org.springframework.security.access.AccessDeniedException;
- import org.springframework.security.access.ConfigAttribute;
- import org.springframework.security.access.vote.AbstractAccessDecisionManager;
- import org.springframework.security.authentication.InsufficientAuthenticationException;
- import org.springframework.security.core.Authentication;
- import org.springframework.security.core.GrantedAuthority;
-
- import java.util.Collection;
- import java.util.Iterator;
- import java.util.List;
-
-
-
-
-
- public class MyAccessDecisionManager extends AbstractAccessDecisionManager {
- protected MyAccessDecisionManager(List<AccessDecisionVoter<? extends Object>> decisionVoters) {
- super(decisionVoters);
- }
-
- @Override
- public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
- if(configAttributes==null){
- return;
- }
- Iterator<ConfigAttribute> ite = configAttributes.iterator();
- while(ite.hasNext()){
- ConfigAttribute ca = ite.next();
- String needRole = (ca).getAttribute();
- for (GrantedAuthority ga : authentication.getAuthorities()){
- if (needRole.equals(ga.getAuthority())){
- return;
- }
- }
- }
- throw new AccessDeniedException("没有权限,拒绝访问!");
- }
- @Override
- public boolean supports(ConfigAttribute attribute) {
- return false;
- }
-
-
-
-
-
-
-
-
-
-
-
- @Override
- public boolean supports(Class<?> clazz) {
- return true;
- }
- }
package com.training.core.security;import org.springframework.security.access.AccessDecisionVoter;import org.springframework.security.access.AccessDeniedException;import org.springframework.security.access.ConfigAttribute;import org.springframework.security.access.vote.AbstractAccessDecisionManager;import org.springframework.security.authentication.InsufficientAuthenticationException;import org.springframework.security.core.Authentication;import org.springframework.security.core.GrantedAuthority;import java.util.Collection;import java.util.Iterator;import java.util.List;/** * Created by Athos on 2016-10-16. */public class MyAccessDecisionManager extends AbstractAccessDecisionManager { protected MyAccessDecisionManager(List<AccessDecisionVoter<? extends Object>> decisionVoters) { super(decisionVoters); } @Override public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if(configAttributes==null){ return; } Iterator<ConfigAttribute> ite = configAttributes.iterator(); while(ite.hasNext()){ ConfigAttribute ca = ite.next(); String needRole = (ca).getAttribute(); for (GrantedAuthority ga : authentication.getAuthorities()){ if (needRole.equals(ga.getAuthority())){ return; } } } throw new AccessDeniedException("没有权限,拒绝访问!"); } @Override public boolean supports(ConfigAttribute attribute) { return false; } /** * Iterates through all <code>AccessDecisionVoter</code>s and ensures each can support * the presented class. * <p> * If one or more voters cannot support the presented class, <code>false</code> is * returned. * * @param clazz the type of secured object being presented * @return true if this type is supported */ @Override public boolean supports(Class<?> clazz) { return true; }}
用户、角色、资源(菜单)略。
详情请看GIT完成工程。
https://github.com/FrameReserve/TrainingBoot