1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
|
@Component public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable {
private static final long serialVersionUID = -8970718410437077606L;
@Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException { int code = HttpStatus.UNAUTHORIZED; String msg = "认证失败,无法访问系统资源,请先登陆"; ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg))); } } 认证流程 自定义认证过滤器
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
private RsaKeyProperties prop;
public TokenLoginFilter(AuthenticationManager authenticationManager, RsaKeyProperties prop) { this.authenticationManager = authenticationManager; this.prop = prop; }
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { try { UserPojo sysUser = new ObjectMapper().readValue(request.getInputStream(), UserPojo.class); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(sysUser.getUsername(), sysUser.getPassword()); return authenticationManager.authenticate(authRequest); }catch (Exception e){ try { response.setContentType("application/json;charset=utf-8"); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); PrintWriter out = response.getWriter(); Map resultMap = new HashMap(); resultMap.put("code", HttpServletResponse.SC_UNAUTHORIZED); resultMap.put("msg", "用户名或密码错误!"); out.write(new ObjectMapper().writeValueAsString(resultMap)); out.flush(); out.close(); }catch (Exception outEx){ outEx.printStackTrace(); } throw new RuntimeException(e); } }
public void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { UserPojo user = new UserPojo(); user.setUsername(authResult.getName()); user.setRoles((List<RolePojo>)authResult.getAuthorities()); String token = JwtUtils.generateTokenExpireInMinutes(user, prop.getPrivateKey(), 24 * 60); response.addHeader("Authorization", "Bearer "+token); try { response.setContentType("application/json;charset=utf-8"); response.setStatus(HttpServletResponse.SC_OK); PrintWriter out = response.getWriter(); Map resultMap = new HashMap(); resultMap.put("code", HttpServletResponse.SC_OK); resultMap.put("msg", "认证通过!"); resultMap.put("token", token); out.write(new ObjectMapper().writeValueAsString(resultMap)); out.flush(); out.close(); }catch (Exception outEx){ outEx.printStackTrace(); } } }
Security默认登录路径为/login,当我们调用该接口时,它会调用上边的attemptAuthentication方法;要自定义UserInfoService继承UserDetailsService实现loadUserByUsername方法;
public interface UserInfoService extends UserDetailsService {
}
@Service @Transactional public class UserInfoServiceImpl implements UserInfoService {
@Autowired private SysUserInfoMapper userInfoMapper;
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { UserPojo user = userInfoMapper.queryByUserName(username); return user; } } 其中的loadUserByUsername返回的是UserDetails类型,所以UserPojo继承UserDetails类
@Data public class UserPojo implements UserDetails {
private Integer id;
private String username;
private String password;
private Integer status;
private List<RolePojo> roles;
@JsonIgnore @Override public Collection<? extends GrantedAuthority> getAuthorities() { List<SimpleGrantedAuthority> auth = new ArrayList<>(); auth.add(new SimpleGrantedAuthority("ADMIN")); return auth; }
@Override public String getPassword() { return this.password; }
@Override public String getUsername() { return this.username; }
@JsonIgnore @Override public boolean isAccountNonExpired() { return true; }
@JsonIgnore @Override public boolean isAccountNonLocked() { return true; }
@JsonIgnore @Override public boolean isCredentialsNonExpired() { return true; }
@JsonIgnore @Override public boolean isEnabled() { return true; } } 当认证通过之后会在SecurityContext中设置Authentication对象,回调调用successfulAuthentication方法返回token信息
自定义token过滤器 public class TokenVerifyFilter extends BasicAuthenticationFilter { private RsaKeyProperties prop;
public TokenVerifyFilter(AuthenticationManager authenticationManager, RsaKeyProperties prop) { super(authenticationManager); this.prop = prop; }
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { String header = request.getHeader("Authorization"); if (header == null || !header.startsWith("Bearer ")) { chain.doFilter(request, response); } else { String token = header.replace("Bearer ", ""); Payload<UserPojo> payload = JwtUtils.getInfoFromToken(token, prop.getPublicKey(), UserPojo.class); UserPojo user = payload.getUserInfo(); if(user!=null){ UsernamePasswordAuthenticationToken authResult = new UsernamePasswordAuthenticationToken(user.getUsername(), null, user.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authResult); chain.doFilter(request, response); } } } }
|