【发布时间】:2021-07-30 02:05:23
【问题描述】:
我使用 REST API 和 JWT 身份验证/授权为我的移动应用程序创建了后端。
然后我使用 Retrofit 创建了 android 应用程序。
从 /login 端点检索 JWToken 后,我在服务器端创建了 GET 请求,以使用令牌解析当前登录用户的用户名,然后在客户端调用方法。
UserController.java(服务器端)
@RestController
@RequestMapping(path = "/user")
public class UserController {
private UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping
public String getCurrentUser(@AuthenticationPrincipal Object user) {
user = SecurityContextHolder.getContext().getAuthentication()
.getPrincipal();
return user.toString();
}
}
但我不确定这样开发它是否正确。
假设我的数据库中有两个表。
- 一个带有用于身份验证的登录凭据
- 其次是用户个人数据
现在我想显示用户的名字和姓氏。
现在,登录后我拥有的唯一信息是他登录时使用的用户名,如果我想获得更多信息,我必须以某种方式在客户端进行查询:
- 首先 - 获取用户 ID,其中 username = 我从令牌中获得的用户名
- 然后 - 从第一个查询中获取 users_data 其中 user_id = id 的对象
我认为这个过程不应该在客户端完成(如果我错了,请纠正我)。
问题
所以我的问题是我应该怎么做才能实现这种情况,我想获取有关用户的所有信息,而我在客户端应用程序中只有他的用户名。我应该在后端进行更改,还是坚持通过移动应用进行查询?
(服务器端)
AuthenticationFilter.java
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
public Authentication attemptAuthentication(
HttpServletRequest request,
HttpServletResponse response
) throws AuthenticationException {
// Mapping credentials to loginviewmodel
LoginViewModel credentials = null;
try {
credentials = new ObjectMapper().readValue(request.getInputStream(), LoginViewModel.class);
} catch (IOException e) {
e.printStackTrace();
}
// Creating login token
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
credentials.getUsername(),
credentials.getPassword(),
new ArrayList<>()
);
// Authenticate user
Authentication auth = authenticationManager.authenticate(authenticationToken);
return auth;
}
@Override
protected void successfulAuthentication(
HttpServletRequest request,
HttpServletResponse response,
FilterChain chain,
Authentication authResult
) throws IOException, ServletException {
// Grab current user
UserImpl principal = (UserImpl) authResult.getPrincipal();
// Create JWT Token
String token = JWT.create()
.withSubject(principal.getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() + JwtProperties.EXPIRATION_TIME))
.sign(Algorithm.HMAC512(JwtProperties.SECRET.getBytes()));
// Add token in response(this is syntax of token)
response.addHeader(JwtProperties.HEADER_STRING, JwtProperties.TOKEN_PREFIX + token);
}
}
AuthorizationFilter.java
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
private UserRepository userRepository;
public JwtAuthorizationFilter(
AuthenticationManager authenticationManager,
UserRepository userRepository
) {
super(authenticationManager);
this.userRepository = userRepository;
}
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain chain
) throws IOException, ServletException {
// Read authorization header with JWT Token
String header = request.getHeader(JwtProperties.HEADER_STRING);
if (header == null || !header.startsWith(JwtProperties.TOKEN_PREFIX)) {
chain.doFilter(request, response);
}
// Try get user data from DB to authorize
Authentication authentication = getUsernamePasswordAuthentication(request);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(request, response);
}
private Authentication getUsernamePasswordAuthentication(HttpServletRequest request) {
String token = request.getHeader(JwtProperties.HEADER_STRING);
if (token != null) {
// parse and validate token
String username = JWT.require(Algorithm.HMAC512(JwtProperties.SECRET.getBytes()))
.build()
.verify(token.replace(JwtProperties.TOKEN_PREFIX, ""))
.getSubject();
if (username != null) {
User user = userRepository.findByUsername(username);
UserImpl principal = new UserImpl(user);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(username, null, principal.getAuthorities());
return auth;
}
return null;
}
return null;
}
}
UserImpl.java
public class UserImpl implements UserDetails {
private User user;
public UserImpl(User user) {
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authorities = new ArrayList<>();
// Get list of roles (ROLE_name)
this.user.getRoleList().forEach( role -> {
GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + role);
authorities.add(authority);
});
return authorities;
}
@Override
public String getPassword() {
return this.user.getPassword();
}
@Override
public String getUsername() {
return this.user.getUsername();
}
}
(客户端)
从当前登录用户解析用户名的方法:
public void getCurrentUser() {
Call<String> call = ApiClient.getUserService(getApplicationContext()).getCurrentUser();
call.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
if (response.isSuccessful()) {
String user = response.body();
nameOfUserView.setText(user);
}
}
@Override
public void onFailure(Call<String> call, Throwable t) {
nameOfUserView.setText(t.getMessage());
}
});
}
【问题讨论】:
标签: java android spring jwt retrofit