spring security ——普通login请求与ajax login请求并存
正常的配置流程就不从头开始说了,网上都有,现在把我遇到的几个问题说一下。
第一个就是当系统进行api调用的时候,或者说Ajax请求时,后台通过判断返回一个json串而不是直接返回一个页面(login.html,403.jsp)。
下面是直接返回页面配置的代码:
<security:http use-expressions="true">
<!--登录和静态资源,任何人都可以访问-->
<security:intercept-url pattern="/login*" access="permitAll"/>
<security:intercept-url pattern="/v*/**" access="permitAll"/>
<!--其它所有页面都要求登录-->
<security:intercept-url pattern="/**" access="isAuthenticated()"/>
<!--<security:intercept-url pattern="/*shtml" access="ROLE_USER"/>-->
<security:form-login
login-page='/login.shtml'
login-processing-url="/j_spring_security_check"
authentication-failure-url="/login-error.shtml"
default-target-url="/main.shtml"
always-use-default-target="true"/>
<security:request-cache ref="requestCache"/>
</security:http>
<bean id="myAuthenticationProvider"
class="***.***.***.MyAuthenticationProvider">
<property name="userDetailsService" ref="myUserDetailsService"/>
<property name="hideUserNotFoundExceptions" value="false"/>
</bean>
<bean id="myUserDetailsService"
class="***.***.***.MyUserDetailsService">
</bean>
<!--认证管理器 用户名密码在MyUserDetailsService中验证-->
<security:authentication-manager>
<security:authentication-provider ref='myAuthenticationProvider'>
</security:authentication-provider>
</security:authentication-manager>
下面是验证部分的实现代码:
public class MyUserDetailsService implements UserDetailsService {
private static final Logger logger = Logger.getLogger(MyUserDetailsService.class);
@Autowired
private UserService userService;
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException {
return buildUser(userName);
}
private MyUserDetails buildUser(String userId) {
Set<String> roleSet = new HashSet<>(1);
HBUser user = userService.selectUser(userId);
if (user == null) {
throw new UsernameNotFoundException("User not exist");
}
roleSet.add(user.getRole());
return new MyUserDetails(user, buildUserAuthority(roleSet));
}
private List<GrantedAuthority> buildUserAuthority(Set<String> userRoles) {
Set<GrantedAuthority> setAuths = new HashSet<>();
// Build user's authorities
for (String userRole : userRoles) {
setAuths.add(new SimpleGrantedAuthority(userRole));
}
return new ArrayList<>(setAuths);
}
}
上面就是前一阶段的配置,后面就是问题的解决部分:
在已有的基础上再加一个<security:http auto-config="true" use-expressions="true" pattern="/rest/**">
表达式语言配置访问控制
<security:http auto-config="true" use-expressions="true" pattern="/r**/**">
<security:form-login
login-processing-url="/r*/s*/login-processing"
login-page="/r*/s*/login-page.do"
authentication-failure-url="/r*/s*/authentication-failure.do"
default-target-url="/r*/s*/default-target.do"
always-use-default-target="true" />
<security:logout logout-url="/r*/s*/logout-url"
logout-success-url="/r*/s*/logout-success.do"/>
<!-- REST services can be secured here, will respond with JSON instead of HTML -->
<!--<security:intercept-url pattern="/rest/calendar/**" access="hasRole('ROLE_USER')" />-->
<!-- other REST intercept-urls go here -->
<security:intercept-url pattern="/rest/security/default-target.do" access="isAuthenticated()" />
<security:intercept-url pattern="/rest/security/*.do" access="permitAll"/>
<security:intercept-url pattern="/rest/engine/**" access="permitAll"/>
<security:intercept-url pattern="/rest/public/**" access="permitAll"/>
<!--相关接口-->
<security:intercept-url pattern="/r*/a*/update.do" access="permitAll"/>
<security:intercept-url pattern="/r*/a*/done.do" access="permitAll"/>
<security:intercept-url pattern="/r*/a*/quiet.do" access="permitAll"/>
<!-- end it with a catch all -->
<security:intercept-url pattern="/rest/**" access="isAuthenticated()" />
<!-- reference to the shared request cache -->
<security:request-cache ref="requestCache"/>
</security:http>
然后我只需要把上面配置中的接口实现就行
只要出现请求配置中的接口就会跳到下面相应的路径
@Controller
@RequestMapping(value = "/r*/s*")
public class RestAuthenticationController {
private static final Logger logger = Logger.getLogger(RestAuthenticationController.class);
@Autowired
UserService userService;
public HttpHeaders getJsonHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
return headers;
}
@RequestMapping(value = "/login-page.do", method = RequestMethod.GET)
public ResponseEntity<String> apiLoginPage() {
return new ResponseEntity<>(getJsonHeaders(), HttpStatus.UNAUTHORIZED);
}
@RequestMapping(value = "/authentication-failure.do", method = RequestMethod.GET)
@ResponseBody
public HBResponse apiAuthenticationFailure(HttpSession session) {
// return HttpStatus.OK to let your front-end know the request completed
// (no 401, it will cause you to go back to login again, loops, not good)
// include some message code to indicate unsuccessful login
Object err = session.getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
HBResponse response;
if (err instanceof UsernameNotFoundException) {
response = new HBResponse(ResultCode.USER_NOT_EXIST, "user not exist.");
} else if (err instanceof BadCredentialsException) {
response = new HBResponse(ResultCode.USERNAME_OR_PASSWORD_ERROR, "password error.");
} else if (err instanceof LockedException) {
response = new HBResponse(ResultCode.SERVER_ERROR, "user locked.");
} else if (err instanceof DisabledException) {
response = new HBResponse(ResultCode.SERVER_ERROR, "user disabled.");
} else if (err instanceof CredentialException) {
response = new HBResponse(ResultCode.SERVER_ERROR, "credintial error: " + err);
} else {
response = new HBResponse(ResultCode.SERVER_ERROR, "unknown error: " + err);
}
return response;
}
第一次写博客,很多东西都不完善,如有错误,请大家多多指正。