最近公司项目快结束了,基本业务都已跑通,现在需要将security安全框架的身份权限验证加入进去。但是在加入以后,自定义登录页面登录成功以后,并不会走继承于UserDetails的自定义类方法,那么security也就获取不到申请者的账号密码信息,也就没法进行身份权限的验证。所以每次自定义的控制层登录验证成功以后都会再次跳入自带的login页面,需要再登录一次才行。一开始以为是自己异步申请的问题,查阅了网上许多相关资料,尝试了许多办法,有说继承SimpleUrlAuthenticationSuccessHandler的,有说因为是ajax请求,所以还需要写个判断是否是ajax申请的。尝试完以后,对于我来说都没有解决我的问题。
问题描述:
security框架,配置了loginPage以后便不断的被拦截重定向至loginPage所配置的页面,不配置loginPage,仅配置defaultSuccessUrl的话,在经过自定义的登录验证后,便会进入到security框架自带的login页面。
解决办法:
- 首先是登录页面:
<body>
<form class="layui-form" id="loginSubmit" method="post" th:action="@{/sys/base/home}" action="sys/base/home">
<!--账号-->
<div class="layui-form-item layui-form-text">
<div class="layui-input-inline">
<input name="username" id="acCode" class="layui-input" type="text" placeholder="请输入账号" autocomplete="off"
lay-verify="required" lay-reqtext="账号是必填项,不能为空!!!"/>
<i class="layui-icon layui-icon-username" style="position: absolute;top:8px;right: 8px;"></i>
</div>
</div>
<!--密码-->
<div class="layui-form-item layui-form-text">
<div class="layui-input-inline">
<input name="password" id="acPwd" class="layui-input" type="password" placeholder="请输入密码" autocomplete="off"
lay-verify="required" lay-reqtext="密码是必填项,不能为空!!!"/>
<i class="layui-icon layui-icon-password" style="position: absolute;top:8px;right: 8px;"></i>
</div>
</div>
<!--验证码-->
<div class="layui-form-item layui-form-text grid-demo grid-demo-bg2">
<div class="layui-input-inline">
<input name="acYZM" id="acYZM" class="layui-input" type="text" placeholder="请输入验证码" autocomplete="off"
lay-verify="required" lay-reqtext="验证码是必填项,不能为空!!!" />
<i class="layui-icon layui-icon-vercode" style="position: absolute;top:8px;right: 8px;"></i>
</div>
</div>
<!--验证码图片-->
<div class="layui-form-item layui-form-text grid-demo grid-demo-bg2">
<div class="layui-input-inline">
<a href="javascript:getVerifiCode()">
<img id="yzm_img" title="点击刷新验证码" src="http://localhost:8099/sysLogin/getVerifiCode"/>
</a>
</div>
</div>
<!--登录按钮-->
<div class="layui-form-item layui-form-text grid-demo grid-demo-bg2">
<div class="layui-input-inline">
<input type="button" class="layui-btn layui-btn-lg" lay-filter="login" lay-submit="" value="登录"/>
</div>
</div>
</form>
</body>
- js部分代码
<script type="text/javascript" th:inline="javascript">
layui.use(['form'], function () {
var form = layui.form;
form.on('submit(login)', function (data) {
var data = {"acCode": $("#acCode").val(), "acPwd": $("#acPwd").val(), "acYZM": $("#acYZM").val()};
$.ajax({
type: "post",
url: '/sys/base/acctLogin',
data: JSON.stringify(data),
datatype: 'json',
contentType: 'application/json',
success: function (result) {
if (成功的情况) {
setTimeout(layer.msg('登录成功'), 3000);
$("#loginSubmit").submit();
} else 失败的情况 {
},
error: function () {
alert("出错,重新跳转故障登记页面");
location.href = '/sysLogin/login'
}
})
});
});
</script>
因为公司没有写前端的,所以使用了layui来写前端页面。
这里说明一下,我是在异步走自定义的控制层方法来判断用户登录成功与否,以及校验验证码的。返回的是一个json对象,传递时后台用对象接收。后台控制层代码就不放了。自己写一下问题不大的。
- securityConfig配置:
@Configuration
@EnableGlobalMethodSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
.
./*此处代码省略,只放上主要配置*/
.
@Bean
UserDetailsService customUserService() { // 注册UserDetailsService 的bean
return new UserAuthService();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers().frameOptions().disable()
.and()
// 禁用CSRF保护
.csrf().disable().authorizeRequests()
.antMatchers("将免验证的路径进行开放").permitAll()
// 任何访问都必须授权
.anyRequest().authenticated()
// 登录路径
.and().formLogin()
.loginPage("被拦截后跳转的页面").permitAll()
.loginProcessingUrl("验证后跳转的页面")
.defaultSuccessUrl("/默认成功后跳转的页面")
.permitAll() //登录页面用户任意访问
// .usernameParameter("acCode").passwordParameter("acPwd")
// 登陆成功后的处理,因为是API的形式所以不用跳转页面
// .successHandler(new RestAuthenticationSuccessHandler())
// 登陆失败后的处理
.failureHandler(new RestAuthenticationFailureHandler()).and()
// 登出后的处理
.logout().logoutSuccessHandler(new RestLogoutSuccessHandler());
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 临时屏蔽加密功能
auth.userDetailsService(customUserService());
// .passwordEncoder(passwordEncoder());
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(将需要开放的配置在内);
}
}
- 实现UserDetailsService类
/**
* 用户鉴权处理
*/
@Component
public class UserAuthService implements UserDetailsService {
/**
* 用户账户服务
*/
@Autowired
private SysBaseService service;
/**
* 加载用户信息
* {@inheritDoc}
*/
@Override
public UserDetails loadUserByUsername(String userCode) throws UsernameNotFoundException {
//此处传来的是用户账号
if (!StringUtils.isEmpty(userCode)) {
/**
* 获得账户相关信息
*/
SysAccountPro acct = service.getAcctByCode(userCode);
if (acct != null) {
这里面判断用户信息啥的,如果用户验证通过,怎返回一个newUser对象。
}
return new User(acct.getAcCode(), acct.getAcPwd(), grantedAuthorities);
} else {
}
} else {
}
}
基本上整体所需要配置的就是这些了,主要在于异步的地方我最后其实还是使用了提交表单的形式。异步去判断账号密码,验证码之类的问题,由提交表单来触发security的验证机制。
如有错误,欢迎纠正。
万般皆下品,唯有读书高。