代码结构 总共涉及到7个类文件
和添加角色配置文件
以及需要在web.xml
中添加一个过滤器(如果是spring boot的话则不需要配置web.xml)
涉及文件及其作用简单分析
role-config.properties
:用来配置所有角色及所持权限信息
Role.java
:将配置文件中的权限信息分装到java类中,方便处理
RoleHandler.java
:构建Role对象列表,以便可以通过配置文件的key获取到相关Role对象
‘UserDtailsBean.java’:根绝具体业务需求来给用户对象添加(自定义)security需要的属性
‘UserDetailsServiceCustom’:自定义用户信息获取服务,主要是重写loadUserByUsername方法
AuthenticationProviderCustom.java
:自定义授权认证类,当用户登录,则会调用该方法,授权操作就是在这里进行的
CustomSuccessHandler
:当登录成功后的处理操作,可以省去或直接跳转到某个页面
SecurityConfig
:Security的核心配置类,在这里使用了自定义的AuthenticationProviderCustom和AuthenticationProviderCustom进行用户信息的构建以及授权类,具体配置内容可参考官网(当然,也可以用XML进行配置,而不是Java Config的形式)
web.xml
:配置security过滤器(使用spring boot的话无须配置)
具体代码案例 1.在配置文件中配置好各个角色的信息,security会默认解析以ROLE_
开头的权限内容作为角色,例如ROLE_ADMIN
,则将作为ADMIN
角色
2.添加角色Bean对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import java.util.List;public class Role { private String name; private List<String> privileges; Role(){ } Role(String name, List<String> privileges){ this .name = name; this .privileges = privileges; } List<String> getPrivileges () { return this .privileges; } String getName () { return name; } public void setName (String name) { this .name = name; } }
3.提供角色权限初始化类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 import com.x.x.common.UserType;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Component;import java.util.ArrayList;import java.util.List;@Component public class RoleHandler { @Value("${role.admin}") private String adminRoleStr; @Value("${role.teacher}") private String teacherRoleStr; @Value("${role.trainee}") private String traineeRoleStr; private final List<Role> roleList = new ArrayList<>(); private void init () { UserType[] userTypes = UserType.values(); Role role; List<String> privilegeList; for (UserType userType : userTypes) { String currentRoleStr; if (userType.equals(UserType.ADMIN)) { currentRoleStr = adminRoleStr; } else if (userType.equals(UserType.TEACHER)) { currentRoleStr = teacherRoleStr; } else if (userType.equals(UserType.TRAINEE)) { currentRoleStr = traineeRoleStr; } else { continue ; } if (currentRoleStr.isEmpty()) { return ; } privilegeList = new ArrayList<>(); String[] roleArr = currentRoleStr.split("," ); for (String s : roleArr) { privilegeList.add(s.trim()); } role = new Role(userType.getRoleName(), privilegeList); roleList.add(role); } } public Role getRole (String roleName) { if (roleList.isEmpty()) { this .init(); } if (roleName == null || roleName.isEmpty()) { return null ; } Role role = new Role(); for (Role temp_role : roleList) { if (temp_role.getName().compareToIgnoreCase(roleName) == 0 ) { role = temp_role; } } return role; } }
4.封装UserDetailBean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 import com.x.x.common.UserType;import com.x.x.entity.User;import com.x.x.util.BeanUtil;import com.x.x.util.SpringContextUtil;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.authority.SimpleGrantedAuthority;import org.springframework.security.core.userdetails.UserDetails;import java.util.ArrayList;import java.util.Collection;public class UserDetailsBean extends User implements UserDetails { public UserDetailsBean (User user) { BeanUtil.copyObjValue(user, this ); } @Override public Collection<? extends GrantedAuthority> getAuthorities() { Collection<SimpleGrantedAuthority> authorities = new ArrayList<>(); RoleHandler roleHandler = SpringContextUtil.getApplicationContext().getBean(RoleHandler.class); if (roleHandler == null ) { return null ; } String roleName; roleName = UserType.getRoleName(this .getUserType()); Role role = roleHandler.getRole(roleName); for (String privilege : role.getPrivileges()) { authorities.add(new SimpleGrantedAuthority(privilege)); } return authorities; } @Override public String getPassword () { return this .getPwd(); } @Override public String getUsername () { return this .getLoginName(); } @Override public boolean isAccountNonExpired () { return true ; } @Override public boolean isAccountNonLocked () { return this .getUserState() == 0 ; } @Override public boolean isCredentialsNonExpired () { return true ; } @Override public boolean isEnabled () { return true ; } }
5.实现UserDetailsService重写loadUserByUsername方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import com.x.x.entity.User;import com.x.x.service.IUserService;import org.slf4j.Logger;import org.slf4j.LoggerFactory;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 javax.annotation.Resource;@Component public class UserDetailsServiceCustom implements UserDetailsService { private Logger logger = LoggerFactory.getLogger(UserDetailsServiceCustom.class); @Resource private IUserService userService; @Override public UserDetails loadUserByUsername (String username) throws UsernameNotFoundException { UserDetailsBean userDetailsBean; User search = new User(); search.setLoginName(username); User user = userService.findOneByEntity(search); if (user==null ) { logger.warn("该用户不存在:" + username); throw new UsernameNotFoundException("该用户不存在:" + username); } else { userDetailsBean = new UserDetailsBean(user); } return userDetailsBean; } }
6.自定义的授权认证类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import com.x.x.entity.User;import com.x.x.service.IUserService;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.security.authentication.AuthenticationProvider;import org.springframework.security.authentication.BadCredentialsException;import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;import org.springframework.security.core.Authentication;import org.springframework.security.core.AuthenticationException;import org.springframework.stereotype.Component;import javax.annotation.Resource;@Component public class AuthenticationProviderCustom implements AuthenticationProvider { private Logger logger = LoggerFactory.getLogger(AuthenticationProviderCustom.class); @Resource private IUserService userService; @Override public Authentication authenticate (Authentication authentication) throws AuthenticationException { UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication; String loginName = token.getName(); String password = token.getCredentials().toString(); User user = userService.getUserByLoginNameAndPwd(loginName, password); UserDetailsBean userDetailsBean; if (user != null ) { userDetailsBean = new UserDetailsBean(user); } else { logger.error("用户名或密码错误" ); throw new BadCredentialsException("用户名或密码错误" ); } return new UsernamePasswordAuthenticationToken(userDetailsBean, password, userDetailsBean.getAuthorities()); } @Override public boolean supports (Class<?> aClass) { return true ; } }
7.配置Security
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.authentication.AuthenticationProvider;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 javax.annotation.Resource;@Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Resource private CustomSuccessHandler customSuccessHandler; @Override protected void configure (HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/**" ).permitAll() .anyRequest().authenticated() .and() .formLogin() .successHandler(customSuccessHandler) .failureUrl("/login?error=true" ) .permitAll() .and() .rememberMe().tokenValiditySeconds(604800 ); http.logout(); http.csrf().disable(); } @Autowired public void configureGlobal (AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(authenticationProvider()); } @Bean @Override protected UserDetailsService userDetailsService () { return new UserDetailsServiceCustom(); } @Bean public AuthenticationProvider authenticationProvider () { return new AuthenticationProviderCustom(); } }
8.自定义成功处理类(可选
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import org.springframework.security.core.Authentication;import org.springframework.security.web.DefaultRedirectStrategy;import org.springframework.security.web.RedirectStrategy;import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;import org.springframework.stereotype.Component;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@Component public class CustomSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); @Override protected void handle (HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { UserDetailsBean user = (UserDetailsBean) authentication.getPrincipal(); String targetUrl; if (UserType.ADMIN.getValue().equals(user.getUserType())) { targetUrl = "/swagger-ui.html" ; } else if (UserType.TEACHER.getValue().equals(user.getUserType())) { targetUrl = "/teacher" ; } else if (UserType.TRAINEE.getValue().equals(user.getUserType())){ targetUrl = "/trainee" ; } else { targetUrl = "/login?error" ; } redirectStrategy.sendRedirect(request, response, targetUrl); } }
9.添加security过滤器
1 2 3 4 5 6 7 8 9 10 <filter > <filter-name > springSecurityFilterChain</filter-name > <filter-class > org.springframework.web.filter.DelegatingFilterProxy</filter-class > </filter > <filter-mapping > <filter-name > springSecurityFilterChain</filter-name > <url-pattern > /*</url-pattern > </filter-mapping >