本文只包涵spring security配置部分,不是一个完整项目,不过可以任意添加到一个web项目中,不需要对原来的程序做任何修改
部分内容来源于网络,如有雷同,毫无意外
1、xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> <global-method-security pre-post-annotations="enabled"> </global-method-security> <!-- 不拦截的路径 --> <http pattern="/registerPage" security="none" /> <http pattern="/mainPage" security="none"></http> <http pattern="/item/itemid**" security="none"></http> <http pattern="/css/**" security="none" /> <http pattern="/font/**" security="none" /> <http pattern="/images/**" security="none" /> <http pattern="/js/**" security="none" /> <http auto-config="true"> <!-- 登录配置 --> <form-login login-page="/loginPage" authentication-failure-url="/login/failure" login-processing-url="/login" authentication-success-handler-ref="mySuccessHandler" username-parameter="username" password-parameter="password" /> <!-- 用户登出 --> <logout invalidate-session="true" logout-success-url="/loginPage" logout-url="/logout" /> <!-- 拦截页面 --> <intercept-url pattern="/item/**" access="ROLE_USER" /> <intercept-url pattern="/admin/**" access="ROLE_USER" /> </http> <!-- 登录成功的处理方法 --> <beans:bean id="mySuccessHandler" class="security.LoginSuccessHandle" ></beans:bean> <!-- 获取UserDettail的bean --> <beans:bean id="UserDetailService" class="security.MyUserDetailService"></beans:bean> <!-- 在这里也是一个大坑,查询网上的文章,这里都是引用的实现了UserDetailsService的类 --> <beans:bean id="UserService" class="security.SecurityProvider"></beans:bean> <authentication-manager> <authentication-provider ref="UserService"> </authentication-provider> </authentication-manager> </beans:beans>
2、用户权限信息类
省略相关数据库代码以及dao层代码
package po; public class UserRole { private String username; private String password; private String role; public UserRole(String username, String password, String role) { super(); this.username = username; this.password = password; this.role = role; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } }
3、MyUserDetail类,实现UserDetail接口,包含用户信息和用户权限类型
package security; import java.util.Collection; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import po.UserRole; public class MyUserDetail implements UserDetails { /** * */ private static final long serialVersionUID = -5619502406659516775L; private UserRole myUser; private Collection<? extends GrantedAuthority> authorities; public MyUserDetail(UserRole user,Collection<? extends GrantedAuthority> authorities) { this.myUser = user; this.authorities = authorities; } public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } public UserRole getMyUser() { return myUser; } public String getPassword() { return myUser.getPassword(); } public String getUsername() { return myUser.getUsername(); } public boolean isAccountNonExpired() { return false; } public boolean isAccountNonLocked() { return false; } public boolean isCredentialsNonExpired() { return false; } public boolean isEnabled() { return false; } }
4、MyUserDetailService类,实现UserDetailsService接口,用来获取一个UserDetail对象
package security; import java.util.ArrayList; import java.util.Collection; 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.Service; import mapper.UserRoleMapper; import po.UserRole; @Service public class MyUserDetailService implements UserDetailsService { @Autowired UserRoleMapper userdao; public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { UserRole user =userdao.getUserByName(username); if(user==null) { throw new UsernameNotFoundException("找不到该用户"); } // Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>(); // SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role); // grantedAuthorities.add(grantedAuthority); return new MyUserDetail(user, getAuthorities(user.getRole())); } private Collection<GrantedAuthority> getAuthorities(String role) { Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>(); SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role); grantedAuthorities.add(grantedAuthority); return grantedAuthorities; } }
5、SecurityProvider类,实现了AuthenticationProvider,返回一个UsernamePasswordAuthenticationToken
package security; import org.springframework.beans.factory.annotation.Autowired; 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.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; public class SecurityProvider implements AuthenticationProvider { @Autowired private MyUserDetailService userDetailsService; public Authentication authenticate(Authentication authentication) throws AuthenticationException { UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication; UserDetails userDetails = userDetailsService.loadUserByUsername(token.getName()); if (userDetails == null) { throw new UsernameNotFoundException("找不到该用户"); } if(!userDetails.getPassword().equals(token.getCredentials().toString())) { throw new BadCredentialsException("用户密码错误"); } return new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(),userDetails.getAuthorities()); } public boolean supports(Class<?> authentication) { return UsernamePasswordAuthenticationToken.class.equals(authentication); } }
6、登录成功后自定义处理过程
spring security可以在配置文件中设置登录成功后的跳转页面,或者是直接返回认证前想要访问的页面,但是因为有时候用户是使用ajax请求登录,所以需要自定义一些操作,我是在登录成功后跳转到控制层url,
在url中携带需要跳转的参数,然后在控制层中将url参数返回到ajax,再由前端重新请求控制层跳转
package security; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.InitializingBean; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.SavedRequest; public class LoginSuccessHandle implements AuthenticationSuccessHandler, InitializingBean { private RequestCache requestCache = new HttpSessionRequestCache(); @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authen) throws IOException, ServletException { SavedRequest savedRequest = requestCache.getRequest(request, response); // 默认认证后跳转路径 String targetUrl = "/mainPage"; // 如果登录前有请求为拦截页面,则验证后跳转到该页面 if (savedRequest != null) { targetUrl = savedRequest.getRedirectUrl(); } // 跳转到认证成功处理控制器 response.sendRedirect("/loginSuccess?url=" + targetUrl); } @Override public void afterPropertiesSet() throws Exception { } }