spring-security4.2实现登录退出以及权限配置
来源:互联网 发布:淘宝开店要交押金吗? 编辑:程序博客网 时间:2024/06/03 15:08
最近用到了spring-security框架来实现登录验证。
以前做登录的步骤是:
1、用户输入用户名、密码登录
2、连接数据库对用户名、密码进行验证
3、获取用户信息(角色列表等等)
4、获取相关操作权限
security安全框架有点不同:
1、用户名、密码组合生成一个AuthenticationToken对象。
2、生成的这个token对象会传递给一个AuthenticationManager对象用于验证。
3、当成功认证后,AuthenticationManager返回一个Authentication对象。
4、接下来,就可以调用AuthenticationSuccessHandler成功处理器跳转首页或者登录之前访问的url。
先上spring-security.xml的配置
<?xml version="1.0" encoding="UTF-8"?><beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xsi:schemaLocation=" http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"> <http pattern="/skin/**" security="none" /> <http pattern="/login.action" security="none" /> <http authentication-manager-ref="authenticationManager" entry-point-ref="customAuthenticationEntryPoint"> <!-- 初始化 --> <intercept-url pattern="/init/**" access="hasRole('ROLE_ADMIN')" /> <!-- 登录 --> <intercept-url pattern="/login.action*" access="permitAll" /> <!-- 用户管理(如果多个权限可以访问就用hasAnyRole('xx','cc')) --> <intercept-url pattern="/user/*.action" access="hasRole('ROLE_ADMIN')" /> <!-- 其他 --> <intercept-url pattern="/**" access="authenticated" /> <!-- 自定义认证过滤器 --> <custom-filter ref="customAuthenticationFilter" position="FORM_LOGIN_FILTER" /> <!-- 自定义退出成功处理器 --> <logout logout-url="/logout.action" success-handler-ref="customLogoutSuccessHandler" /> <headers> <!-- Iframe页面允许被其它页面嵌入 --> <frame-options disabled="true" /> </headers> <csrf disabled="true" /> </http> <!-- 认证管理器 --> <authentication-manager alias="authenticationManager"> <authentication-provider ref="customAuthenticationProvider" /> </authentication-manager> <!-- 认证服务提供者 --> <beans:bean id="customAuthenticationProvider" class="com.identity.security.CustomAuthenticationProvider" /> <!-- 认证入口点 --> <beans:bean id="customAuthenticationEntryPoint" class="com.identity.security.CustomAuthenticationEntryPoint"> <beans:constructor-arg name="pcLoginUrl" value="/login.action" /> </beans:bean> <!-- 认证过滤器 --> <beans:bean id="customAuthenticationFilter" class="com.identity.security.CustomAuthenticationFilter"> <beans:constructor-arg name="filterProcessesUrl" value="/doLogin.action" /> <beans:property name="authenticationSuccessHandler" ref="customAuthenticationSuccessHandler" /> <beans:property name="authenticationFailureHandler" ref="customAuthenticationFailureHandler" /> <beans:property name="authenticationManager" ref="authenticationManager" /> </beans:bean> <!-- 登录认证成功处理器 --> <beans:bean id="customAuthenticationSuccessHandler" class="com.identity.security.CustomAuthenticationSuccessHandler" /> <!-- 登录认证失败处理器 --> <beans:bean id="customAuthenticationFailureHandler" class="com.identity.security.CustomAuthenticationFailureHandler" /> <!-- 退出登录处理器 --> <beans:bean id="customLogoutSuccessHandler" class="com.identity.security.CustomLogoutSuccessHandler" /></beans:beans>
先配置一个自定义登录页面
package com.identity.security;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;/** * 自定义认证入口点 * */public class CustomAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint { /** * 构造方法 * * @param pcLoginUrl 登录页 */ public CustomAuthenticationEntryPoint(String pcLoginUrl) { super(pcLoginUrl); } @Override protected String determineUrlToUseForThisRequest(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) { return super.determineUrlToUseForThisRequest(request, response, exception); }}
创建一个自定义的token对象类
package com.identity.security;import org.springframework.security.authentication.AbstractAuthenticationToken;import com.identity.entitys.UserInfo;/** * 自定义认证token * */public class CustomAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = 1L; /** Principal */ private Object principal; /** 帐号 */ private String username; /** 密码 */ private String password; /** 登录IP */ private String loginIp; /** 构造方法,未通过登录认证 */ public CustomAuthenticationToken() { super(null); this.principal = null; super.setAuthenticated(false); } /** 构造方法,已经通过登录认证 */ public CustomAuthenticationToken(UserInfo user) { super(user.getAuthoritys()); this.principal = user; super.setAuthenticated(true); } /** * 获取帐号 * * @return username 帐号 */ public String getUsername() { return username; } /** * 设置帐号 * * @param username 帐号 */ public void setUsername(String username) { this.username = username; } /** * 获取密码 * * @return password 密码 */ public String getPassword() { return password; } /** * 设置密码 * * @param password 密码 */ public void setPassword(String password) { this.password = password; } /** * 获取登录IP * * @return loginIp 登录IP */ public String getLoginIp() { return loginIp; } /** * 设置登录IP * * @param loginIp 登录IP */ public void setLoginIp(String loginIp) { this.loginIp = loginIp; } @Override public Object getCredentials() { return null; } @Override public Object getPrincipal() { return this.principal; }}
用户输入完账号密码后会先进这个认证滤器生成我们定义好的token对象
package com.identity.security;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.lang.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.security.core.Authentication;import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;/** * 自定义认证过滤器 */public class CustomAuthenticationFilter extends AbstractAuthenticationProcessingFilter { private static final Logger LOGGER = LoggerFactory.getLogger(CustomAuthenticationFilter.class); /** 构造方法,设置登录URL */ public CustomAuthenticationFilter(String filterProcessesUrl) { super(filterProcessesUrl); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { try { CustomAuthenticationToken token = new CustomAuthenticationToken(); token.setUsername(request.getParameter("username")); token.setPassword(request.getParameter("password")); token.setLoginIp(getRequestIp(request)); token.setDetails(authenticationDetailsSource.buildDetails(request)); return this.getAuthenticationManager().authenticate(token); } catch (CustomAuthenticationException e) { throw e; } catch (Exception e) { LOGGER.error("登录过程异常,请求参数为[" + request + "]", e); throw new CustomAuthenticationException("登录失败,服务器内部错误,请稍后再试..."); } } /** 获取请求客户端真实IP */ public String getRequestIp(HttpServletRequest request) { String ip = request.getHeader("X-Forwarded-For"); if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return ip; }}
然后过滤器把这个Authentication对象传递给AuthenticationProvider去处理
package com.identity.security;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.security.authentication.AuthenticationProvider;import org.springframework.security.core.Authentication;import org.springframework.security.core.AuthenticationException;import org.springframework.transaction.annotation.Transactional;import com.identity.entitys.LoginLog;import com.identity.entitys.UserInfo;import com.identity.querys.impl.UserInfoQueryImpl;/** * 自定义认证服务提供者 * */public class CustomAuthenticationProvider implements AuthenticationProvider { private static final Logger LOGGER = LoggerFactory.getLogger(CustomAuthenticationProvider.class); @Override @Transactional() public Authentication authenticate(Authentication authentication) throws AuthenticationException { try { CustomAuthenticationToken token = (CustomAuthenticationToken) authentication; UserInfo user = retrieveUser(token); preAuthenticationCheck(token, user); additionalAuthenticationCheck(token, user); postAuthenticationCheck(token, user); saveLoginLog(token, user); CustomAuthenticationToken result = new CustomAuthenticationToken(user); result.setDetails(authentication.getDetails()); return result; } catch (CustomAuthenticationException e) { throw e; } catch (Exception e) { LOGGER.error("登录认证异常,Token为[" + authentication + "]", e); throw new CustomAuthenticationException("登录失败,服务器内部错误,请稍后再试...", e); } } @Override public boolean supports(Class<?> authentication) { return CustomAuthenticationToken.class.isAssignableFrom(authentication); } /** 检索用户 */ private UserInfo retrieveUser(CustomAuthenticationToken token) { //这里是进数据库根据账号查用户 UserInfo user = null; user = new UserInfoQueryImpl().username(token.getUsername(),false).uniqueResult(); return user; } /** 前置的身份认证检查 */ private void preAuthenticationCheck(CustomAuthenticationToken token, UserInfo user) { if (user == null) { throw new CustomAuthenticationException("登录失败,帐号不存在"); } if (!user.isEnabled()) { throw new CustomAuthenticationException("登录失败,您的帐号已被禁用"); } if (!user.isAccountNonExpired()) { throw new CustomAuthenticationException("登录失败,您的帐号已过期"); } } /** 后置的身份认证检查 */ private void postAuthenticationCheck(CustomAuthenticationToken token, UserInfo user) { if (!user.isCredentialsNonExpired()) { throw new CustomAuthenticationException("登录失败,您的密码已过期"); } } /** 额外的身份认证检查 */ public void additionalAuthenticationCheck(CustomAuthenticationToken token, UserInfo user) { if (!user.isRealPassword(token.getPassword())) { throw new CustomAuthenticationException("帐号或密码错误"); } } /** 保存登录日志 */ public void saveLoginLog(CustomAuthenticationToken token, UserInfo user) { LoginLog loginLog = new LoginLog(); loginLog.setIp(token.getLoginIp()); loginLog.setUser(user); loginLog.saveOrUpdateIt(); }}
在AuthenticationProvider里面验证后会进入登录成功或者失败处理器
package com.identity.security;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import net.sf.json.JSONObject;import org.apache.commons.lang.StringUtils;import org.springframework.security.core.Authentication;import org.springframework.security.web.WebAttributes;import org.springframework.security.web.authentication.AuthenticationSuccessHandler;import org.springframework.security.web.savedrequest.DefaultSavedRequest;import org.springframework.security.web.savedrequest.HttpSessionRequestCache;import org.springframework.security.web.savedrequest.RequestCache;/** * 自定义登录认证成功处理器 * */public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler { private RequestCache requestCache = new HttpSessionRequestCache(); @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { response.setContentType("text/html;charset=UTF-8"); JSONObject jsonObject = new JSONObject(); String targetUrl = request.getParameter("to"); if (StringUtils.isEmpty(targetUrl)) { DefaultSavedRequest savedRequest = (DefaultSavedRequest) this.requestCache.getRequest(request, response); if (savedRequest != null) { targetUrl = savedRequest.getRequestURI() + "?" + savedRequest.getQueryString(); } else { targetUrl = request.getContextPath() + "/index.action"; } } else { this.requestCache.removeRequest(request, response); } clearAuthenticationAttributes(request); jsonObject.put("staut", true); jsonObject.put("targetUrl", targetUrl); response.getWriter().write(jsonObject.toString()); } /** 删除身份认证临时数据 */ protected final void clearAuthenticationAttributes(HttpServletRequest request) { HttpSession session = request.getSession(false); if (session == null) { return; } session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION); }}
package com.identity.security;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import net.sf.json.JSONObject;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.authentication.AuthenticationFailureHandler;/** * 自定义登录认证失败处理器 * */public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler { private static final Logger LOGGER = LoggerFactory.getLogger(CustomAuthenticationFailureHandler.class); @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { response.setContentType("text/html;charset=UTF-8"); String errorMsg = null; JSONObject jsonObject = new JSONObject(); if (exception instanceof CustomAuthenticationException) { errorMsg = exception.getMessage(); } else { LOGGER.error("登录异常,请求参数为[" + request + "]", exception); errorMsg = "登录失败,服务器内部错误,请稍后再试..."; } jsonObject.put("staut", false); jsonObject.put("errorMsg", errorMsg); response.getWriter().write(jsonObject.toString()); }}
自定义异常类
package com.identity.security;import org.springframework.security.core.AuthenticationException;/** * 自定义认证异常 * */public class CustomAuthenticationException extends AuthenticationException { private static final long serialVersionUID = 1L; public CustomAuthenticationException(String msg) { super(msg); } public CustomAuthenticationException(String msg, Throwable t) { super(msg, t); }}
然后是退出
package com.identity.security;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import net.sf.json.JSONObject;import org.apache.commons.lang.StringUtils;import org.springframework.security.core.Authentication;import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;/** * 自定义退出登录处理器 * */public class CustomLogoutSuccessHandler implements LogoutSuccessHandler { @Override public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { response.setContentType("text/html;charset=UTF-8"); JSONObject jsonObject = new JSONObject(); String url = request.getParameter("to"); if (StringUtils.isEmpty(url)) { url = request.getContextPath() + "/login.action?logout=true"; } jsonObject.put("staut", true); jsonObject.put("url", url); response.getWriter().write(jsonObject.toString()); }}
然后用户和权限实体多对多的关系就行了,权限表的权限名记得是ROLE_XX的格式。完成以上的配置基本上登录退出就完成了~~
阅读全文
1 0
- spring-security4.2实现登录退出以及权限配置
- 【Spring实战】----Security4.1.3实现根据请求跳转不同登录页以及登录后根据权限跳转到不同页配置
- 【Spring实战】----Security4.1.3实现根据请求跳转不同登录页以及登录后根据权限跳转到不同页配置
- spring security4.2 配置CSRF防御
- spring security4 详细配置
- Spring Security4的配置,以及一些吐槽.(一)
- Spring Security4的配置,以及一些吐槽.(二)
- spring security4 之 简单配置
- Spring boot +Spring security4 config 配置同账号登录只允许一个在线
- Spring security4.1.0 自定义角色和权限
- 【Spring实战】----spring security4.1.3配置以及踩过的坑
- spring security起步四:退出登录配置以及logout属性详解
- spring security起步四:退出登录配置以及logout属性详解
- Spring Security4.1.3实现拦截登录后向登录页面跳转方式(redirect或forward)返回被拦截界面
- Spring Security4.1.3实现拦截登录后向登录页面跳转方式(redirect或forward)返回被拦截界面
- 【spring-security】spring-security4安全框架配置详解
- spring security 登录、权限管理配置
- spring security 登录、权限管理配置
- 软件测试知识
- laravel框架总结 -- 返回值
- (字符串匹配)Codeforces Round #425 B. Petya and Exam
- 使用PLSQL Developer查看Oracle数据库中文乱码解决方案
- Android和H5交互
- spring-security4.2实现登录退出以及权限配置
- css中和图片相关的样式
- Linux内核分析-6/进程fork
- MongoDB(可视化推荐)
- xStream完美转换XML、JSON
- 开源软件执照检查和工具探讨(Discuss the audit tools for open source license GPL/LGPL/MIT)
- SAS如何计算经纬度之间的距离
- <机器学习>(周志华)读书笔记 -- 第六章 支持向量机
- C