1. Сценарий
Front-end и back-end разделены, как обеспечить безопасность взаимодействия данных?
Кто-то: жетон
Такие клиенты, как мобильные терминалы, небольшие программы и H5, также передаются через данные JSON, что также включает проверку личности.
Во-вторых, проблема
Как реализовать Токен, это лучший способ?
Опыт работы в сотнях проектов (.(▼へ▼メ) претенциозный.) Я видел много проектов, реализованных таким образом
- жетон? Нам не нужно
- Токен прописывается насмерть, а фон предоставляется клиенту (их действительно много)
- Токен динамический, а фон генерирует токен по какому-то алгоритму и предоставляет его клиенту (этот метод не невозможен, но он не идеален)
- Все данные JSON шифруются и передаются, а ключ предоставляется в фоновом режиме (эм.... не оценивается)
- и т.д
3. Решения
Сегодня мы объясним использованиеJWT, чтобы решить проблему с токеном
#Наука о JWT
JSON Web Token (JWT)Открытый стандарт на основе JSON для передачи информации между веб-приложениями.(RFC 7519), используемый для безопасной передачи информации между различными системами в виде объектов JSON. Основной сценарий использования обычно используется для передачи аутентифицированной информации об удостоверении пользователя между поставщиками удостоверений и поставщиками услуг.
JWT состоит из трех частей, а именно:
- ЗаголовокСодержит две части: тип токена и используемый алгоритм подписи.
- Полезная нагрузкаЭто определяемый пользователем контент, переносимый токеном.Данные представлены в формате base64, не зашифрованы, могут быть взломаны и не могут хранить конфиденциальную информацию; чем больше контента, тем длиннее токен.
- ПодписьОбъедините Header+Payload в строку и вычислите ее с помощью указанного алгоритма подписи, чтобы получить значение подписи.Сервер может использовать этот флаг, чтобы определить, является ли токен законным или нет.
# Объясните безопасность Spring (бонус)
Для решения проблемы с токеном есть JWT.В сочетании с Spring Security он может решить проблему модулей разрешений пользователей (действительно очень мощных).Конечно, помимо Spring Security, Apache Shiro также может решать разрешения, но это не так мощный, как безопасность.
В-четвертых, метод реализации
Внедрить банку зависимостей JWT и Spring Security в pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
Класс инструмента JWT, создание токена, проверка токена, обновление токена и т. д.
@Component
public class JwtTokenUtil {
private static final String CLAIM_KEY_USERNAME = "sub";
private static final String CLAIM_KEY_CREATED = "created";
// 生成token
public String generateToken(UserDetails userDetails) {
...
}
// 刷新token
public String refreshToken(String token) {
...
}
// 校验token
public Boolean validateToken(String token) {
...
}
}
Фильтр токенов, который обрабатывает токен интерфейса.
@Component
public class JwtTokenFilter extends OncePerRequestFilter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Override
protected void doFilterInternal (HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
String authHeader = request.getHeader(Constant.HEADER_STRING );
if (authHeader != null && authHeader.startsWith(Constant.TOKEN_PREFIX )) {
final String authToken = authHeader.substring(Constant.TOKEN_PREFIX.length() );
String username = jwtTokenUtil.getUsernameFromToken(authToken);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (jwtTokenUtil.validateToken(authToken, userDetails)) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(
request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}
chain.doFilter(request, response);
}
}
Основная конфигурация Spring Security
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true, securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userService;
@Bean
public JwtTokenFilter authenticationTokenFilterBean() throws Exception {
return new JwtTokenFilter();
}
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(new BCryptPasswordEncoder());
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
String[] urls = new String[]{"/user/login", "/user/register"};
httpSecurity.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
// 允许注册和登录接口不需token访问
.antMatchers(urls).permitAll()
.anyRequest().authenticated();
httpSecurity.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
httpSecurity.headers().cacheControl();
}
}
Проверка разрешений, если интерфейсу необходимо ограничивать ограничения доступа, добавьте @PreAuthorize
@RestController
public class RoleController {
/**
* 测试普通权限
*
* @return
*/
@PreAuthorize("hasAuthority('ROLE_NORMAL')")
@GetMapping(value="/normal/test")
public String test1() {
return "普通角色访问";
}
/**
* 测试管理员权限
*
* @return
*/
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
@GetMapping(value = "/admin/test")
public String test2() {
return "管理员访问";
}
}
Вам необходимо добавить роль пользователю для доступа, как показано ниже: Таблица взаимосвязей ролей пользователей
5. Как проверить токен
Примечание. JWT по умолчанию не зашифрован, его может прочитать любой, вы можете скопировать строку токенов вОнлайн расшифровка JWT
eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJPd2F0ZXIiLCJjcmVhdGVkIjoxNTYzMzc2ODE2NTIzLCJleHAiOjE1NjMzODQwMTZ9.SuL4dRoweriLOnZzohcEzUwXf7kVSx9KnTIGtB7ffuBtlUUFS1T8il7_fxv3Gn1LkX5DGOawqNhG4ZWYxALDig
Как видно из вышеизложенного, информация, хранящаяся в токене, может быть разобрана, поэтому никому не следует хранить здесь конфиденциальную информацию.
Тогда токен не будет подделан? Нет, потому что в трех частях токена (заголовок, полезная нагрузка, подпись) можно предотвратить подделку подписи, этот ключ известен только серверу.
6. Тестовый эффект
- Вернуть токен после успешного входа
- Без токена доступ будет запрещен
- правильный способ доступа