具体实现步骤 (可按照以下步骤傻瓜式操作一遍成功后自行调整)
- 前端url携带ssoCode
- ssoCode通过DES加密生成(加密方式自行选择)
- 在 src/permission.js 文件中加上以下代码
- 在 store/modules/user.js 文件中的 actions 加上以下代码
- 在 api/login.js 文件中 加上以下代码
- 在后端中新增类 SsoLoginController 并加上以下代码
@RestController
@RequestMapping("/sso")
public class SsoLoginController {
@Autowired
private ISysUserService userService;
@Autowired
private SysLoginService loginService;
@PostMapping("/login")
@ApiOperation(value = "单点登录")
public AjaxResult toThirdPartGetAuthJHaveToken(@RequestBody JSONObject loginInfo) {
String userName = "admin";
SysUser sysUser = userService.selectUserByUserName(userName);
if (sysUser == null) {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGIN_FAIL, "用户不存在!"));
return AjaxResult.error("用户不存在!");
}
AjaxResult ajax = AjaxResult.success();
String token = loginService.login(sysUser.getUserName(), "ssoLogin");
ajax.put(Constants.TOKEN, token);
return ajax;
}
}
- 在类SysLoginService中加上login重载方法 代码如下
public String login(String username, String password)
{
Authentication authentication = null;
try
{
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
AuthenticationContextHolder.setContext(authenticationToken);
authentication = authenticationManager.authenticate(authenticationToken);
}
catch (Exception e)
{
if (e instanceof BadCredentialsException)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
}
else
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
throw new ServiceException(e.getMessage());
}
}
finally
{
AuthenticationContextHolder.clearContext();
}
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
recordLoginInfo(loginUser.getUserId());
return tokenService.createToken(loginUser);
}
- 通过分析 UserDetailsServiceImpl 的 loadUserByUsername 方法得知 需要改造 SysPasswordService 的 validate方法
- 新增 SpringSecurity 身份认证提供者类 SsoAuthenticationProvider 并加上以下代码
@Component
public class SsoAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserDetailsService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String userName = authentication.getName();
String password = authentication.getCredentials().toString();
if ("ssoLogin".equals(password)) {
UserDetails user = userDetailsService.loadUserByUsername(userName);
return new SsoAuthenticationToken(user, password, user.getAuthorities());
}
UserDetails user = userDetailsService.loadUserByUsername(userName);
if (user != null && user.getPassword().equals(password)) {
return new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities());
}
return null;
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
- 新增 SpringSecurity 身份验证令牌类SsoAuthenticationToken 并加上以下代码
public class SsoAuthenticationToken extends UsernamePasswordAuthenticationToken {
public SsoAuthenticationToken(Object principal, Object credentials) {
super(principal, credentials);
}
public SsoAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
super(principal, credentials, authorities);
}
}
- 在 SecurityConfig 中按下图中配置