使用spring security的时候,框架会帮我们做账户密码的验证,但是如我们需要添加一个验证码,就需要对配置文件进行修改,自己写一个方法在验证账户密码之前验证验证码。(关键是提取authenticationManager身份认证管理器,然后在身份验证之前进行验证码验证,然后再交给验证器验证账号密码)
具体操作如下:
在applicationContext-security.xml:
重点是配置验证入口那里
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- ########## 配置Http请求URL拦截规则 ########### -->
<!-- 配置哪些请求URL不需要拦截,看自己需要配置 -->
<security:http pattern="/css/**" security="none"/>
<security:http pattern="/img/**" security="none"/>
<security:http pattern="/js/**" security="none"/>
<security:http pattern="/plugins/**" security="none"/>
<security:http pattern="/*.html" security="none"/>
<security:http pattern="*.xml" security="none"/>
<security:http pattern="/seller/save" security="none"/>
<security:http pattern="/user/checkCode" security="none"/>
<!-- 配置哪些请求URL需要拦截 -->
<!--设置认证器入口为自己的beanauthenticationEntryPoint-->
<security:http auto-config="false" entry-point-ref="authenticationEntryPoint" use-expressions="true">
<security:intercept-url pattern="/user/login" access="permitAll"/>
<!-- 配置剩余的请求URL需要拦截,先登录,再获取角色 ROLE_* -->
<security:intercept-url pattern="/**" access="hasRole('SELLER')"/>
<!-- 配置表单登录
登录成功后重定向
default-target-url
always-use-default-target
-->
<security:form-login
login-page="/shoplogin.html"
default-target-url="/admin/index.html"
always-use-default-target="true"
authentication-failure-url="/shoplogin.html"/>
<!-- 关闭跨站点请求伪造 -->
<security:csrf disabled="true"/>
<!-- 配置请求头 -->
<security:headers>
<!-- 配置同一个域名下,可以访问iframe子窗口 SAMEORIGIN same origin-->
<security:frame-options policy="SAMEORIGIN"/>
</security:headers>
<!-- 配置退出 -->
<security:logout logout-url="/logout" invalidate-session="true"/>
</security:http>
<!-- 配置认证入口 -->
<bean id="authenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<!-- 配置认证处理请求地址 -->
<constructor-arg value="/user/login"/>
</bean>
<!-- ########## 配置身份认证管理器 ########### -->
<!-- 配置认证管理器 -->
<security:authentication-manager id="authenticationManager">
<!-- 配置认证提供者 -->
<security:authentication-provider user-service-ref="userDetailsService">
<!-- 设置加密方式 -->
<security:password-encoder ref="passwordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>
<!-- 配置密码加密 -->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
<!-- 配置服务消费者 -->
<dubbo:application name="shop-web"/>
<!-- 配置zookeeper注册中心,发现服务 -->
<dubbo:registry address="zookeeper://192.168.12.131:2181"/>
<!-- 配置引用单个服务,产生服务接口代理对象 -->
<dubbo:reference id="sellerService" interface="service.SellerService"/>
<!-- 配置自定义的用户认证服务 -->
<bean id="userDetailsService" class="shop.service.UserDetailsServiceImpl">
<property name="sellerService" ref="sellerService"/>
</bean>
</beans>
controller中(生成验证码的方法(/user/checkCode),跟验证验证码(/user/login)的方法我写在了一起):
(提取好authenticationManager身份认证管理器之后,就可以自行认证
在控制层写一个/login方法)
/**
* 获取登录用户名控制器
*/
@Controller
@RequestMapping("/user")
public class LoginController {
/**
* 注入身份认证管理器
*/
@Autowired
private AuthenticationManager authenticationManager;
/**
* 登录认证
*/
@RequestMapping("/login")
public void login(String username, String password, String check, HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println(check);
if (check== null || !request.getSession().getAttribute("CHECKCODE_SERVER").toString().equals(check)) {
response.sendRedirect("/shoplogin.html");
return;
}
if (request.getMethod().equalsIgnoreCase("post")) {
System.out.println(username + "==" + password + "==" + check);
// 创建用户名与密码认证对象
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
try {
// 调用认证方法,返回认证对象
Authentication authenticate = authenticationManager.authenticate(token);
// 判断是否认证成功
if (authenticate.isAuthenticated()) {
// 设置用户认证成功,往Session中添加认证通过信息
SecurityContextHolder.getContext().setAuthentication(authenticate);
// 重定向到登录成功页面
response.sendRedirect("/admin/index.html");
return;
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
// 重定向到登录页面
response.sendRedirect("/shoplogin.html");
return;
}
@RequestMapping("/checkCode")
public void code(HttpServletRequest request, HttpServletResponse response) throws IOException {
//服务器通知浏览器不要缓存
//在内存中创建一个长80,宽30的图片,默认黑色背景
//参数一:长
//参数二:宽
//参数三:颜色
int width = 80;
int height = 30;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//获取画笔
Graphics g = image.getGraphics();
//设置画笔颜色为灰色
g.setColor(Color.GRAY);
//填充图片
g.fillRect(0, 0, width, height);
//产生4个随机验证码,12Ey
String checkCode = getCheckCode();
//将验证码放入HttpSession中
request.getSession().setAttribute("CHECKCODE_SERVER", checkCode);
//设置画笔颜色为黄色
g.setColor(Color.YELLOW);
//设置字体的小大
g.setFont(new Font("黑体", Font.BOLD, 24));
//向图片上写入验证码
g.drawString(checkCode, 15, 25);
//将内存中的图片输出到浏览器
//参数一:图片对象
//参数二:图片的格式,如PNG,JPG,GIF
//参数三:图片输出到哪里去
ImageIO.write(image, "PNG", response.getOutputStream());
}
/**
* 产生4位随机字符串
*/
private String getCheckCode() {
String base = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
int size = base.length();
Random r = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 1; i <= 4; i++) {
//产生0到size-1的随机值
int index = r.nextInt(size);
//在base字符串中获取下标为index的字符
char c = base.charAt(index);
//将c放入到StringBuffer中去
sb.append(c);
}
return sb.toString();
}
}
前端:注册一个点击事件,用于生成新的图片验证码
<div class="verify">
<input name="check" type="text"
placeholder="请输入验证码" autocomplete="off">
<span><img src="/user/checkCode" alt=""
onclick="changeCheckCode(this)">
</span>
<script type="text/javascript">
//图片点击事件
function changeCheckCode(img) {
img.src = "/user/checkCode?" + new Date().getTime();
}
</script>
</div>