静态页优秀网站,企业宣传片文案大全,网络优化seo是什么工作,一键建站免费目录 前言1. 基本知识2. Demo3. 实战 前言 #x1f91f; 找工作#xff0c;来万码优才#xff1a;#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 1. 基本知识
Bearer Token是一种基于Token的认证机制#xff0c;用于在HTTP请求中传递用户的身份信息
应用于RESTful A… 目录 前言1. 基本知识2. Demo3. 实战 前言 找工作来万码优才 #小程序://万码优才/r6rqmzDaXpYkJZF 1. 基本知识
Bearer Token是一种基于Token的认证机制用于在HTTP请求中传递用户的身份信息
应用于RESTful API和各种Web应用中提供了一种轻量且高效的身份验证方式
基本的作用如下
身份验证通过Token验证用户的身份确定其是否有权访问某个资源授权Token中可以包含用户的权限信息服务器可以根据Token中的信息决定用户可以进行的操作无状态认证服务器不需要保存用户的会话状态只需解析Token即可验证用户身份使系统更易于扩展和管理
具体的工作原理如下
用户登录用户向服务器发送登录请求提供用户名和密码等认证信息Token生成服务器验证用户信息后生成一个包含用户身份和权限信息的Bearer Token。 Token可以是纯字符串也可以是经过签名的JWTJSON Web TokenToken传输服务器将生成的Token返回给客户端客户端将其存储在本地如浏览器的Local Storage或Cookie中请求资源客户端在后续的HTTP请求中将Bearer Token放在Authorization头中发送到服务器Token验证服务器接收到请求后提取Bearer Token解析其内容以验证用户身份和权限决定是否允许请求
融入个人的一点小思考 Uni-app部分由于它是跨平台的框架语法和Vue类似我可以使用类似的逻辑来实现登录和.Token的管理。只需确保在不同设备上的本地存储方式一致即可。 在后端使用Java开发时我需要编写一个控制器来处理登录请求生成Token并将其返回给前端。同时还需要编写过滤器或拦截器用于检查每个请求的Authorization头解析Token并验证。如果Token有效则允许请求继续否则拒绝访问。 那么如何辨别前端传来的Token是否有效呢在后端可以利用JWT的特性比如检查Token的签名是否正确Token是否过期以及Token中的用户信息是否合法。也可以实现Token的黑名单机制支持用户注销或停止某些Token的使用。 在实际项目中还需要考虑Token的安全性比如防止CSRF攻击、存储Token的方式本地存储、Cookie等、Token的有效期等。此外还需要应对Token被泄露或被截获的风险建议在传输中使用HTTPS协议。 经过以上的思考我对Bearer Token有了基本的理解。它是一种基于Token的认证方式适用于分布式系统和无状态的API设计。通过Token的生成、存储和验证可以在没有会话管理的情况下实现用户的身份认证 ~ 具体JWT的流程如下 前端发送登录请求包含用户名和密码 后端验证用户信息创建Header和Payload 使用保密密钥对Header和Payload进行签名生成完整的JWT 将JWT返回给前端前端存储它
~ jwt验证流程 前端在每次请求中携带JWT 后端提取JWT验证其签名确保未被篡改 解析Payload中的用户信息进行权限检查
2. Demo
接下来会以Vue 以及 Uniapp对接Java的方式呈现一个Demo主要是提供一个思路
实现Bearer Token的步骤
用户登录客户端发送登录请求携带用户名和密码服务器验证用户信息成功后生成Bearer Token返回Token给客户端存储Token客户端将Token存储在安全的位置如HTTP-only Cookie或Local Storage中确保Token不会被恶意脚本窃取推荐使用HTTPS传输发送请求客户端在后续请求中在Authorization头添加Bearer 服务器接收到请求后解析Token验证用户身份Token验证服务器检查Token的签名是否有效确保Token未被篡改验证Token是否过期获取用户信息和权限授权或拒绝请求
Bearer Token的过期与刷新 过期时间定义Token的存活时间通常几分钟到几小时不等。Token过期后用户需要重新登录以获取新的Token 刷新Token用户在Token过期前可以请求刷新Token获取新的有效Token
Vue实现
登录组件
templatediv classloginh2登录/h2form submit.preventhandleLogindiv classform-grouplabel forusername用户名/labelinput typetext idusername v-modelusername required/divdiv classform-grouplabel forpassword密码/labelinput typepassword idpassword v-modelpassword required/divbutton typesubmit登录/button/form/div
/templatescript
export default {data() {return {username: ,password: };},methods: {async handleLogin() {try {const response await this.$axios.post(/api/login, {username: this.username,password: this.password});const token response.data.token;localStorage.setItem(authToken, token);this.$router.push(/dashboard);} catch (error) {console.error(登录失败:, error);}}}
};
/script请求拦截器
// main.js
import Vue from vue;
import axios from axios;axios.interceptors.request.use(config {const token localStorage.getItem(authToken);if (token) {config.headers.Authorization Bearer ${token};}return config;
});Vue.config.productionTip false;
new Vue({render: h h(App),
}).$mount(#app);Uni-app实现
登录页面
templateview classloginh2登录/h2form submithandleLoginview classform-grouplabel用户名/labelinput typetext v-modelusername //viewview classform-grouplabel密码/labelinput typepassword v-modelpassword //viewbutton form-typesubmit登录/button/form/view
/templatescript
export default {data() {return {username: ,password: };},methods: {async handleLogin() {try {const response await this.$axios.post(/api/login, {username: this.username,password: this.password});const token response.data.token;uni.setStorageSync(authToken, token);uni.navigateTo({ url: /pages/dashboard/dashboard });} catch (error) {console.error(登录失败:, error);}}}
};
/scriptUni-app 请求拦截器
// app.vue
import Vue from vue;
import axios from axios;axios.interceptors.request.use(config {const token uni.getStorageSync(authToken);if (token) {config.headers.Authorization Bearer ${token};}return config;
});Vue.config.productionTip false;App.mpType app;const app new Vue({...App
});app.$mount();四、后端实现Java
User实体类
AllArgsConstructor
NoArgsConstructor
Data
Entity
public class User {IdGeneratedValue(strategy GenerationType.IDENTITY)private Long id;private String username;private String password;Enumerated(EnumType.STRING)private Role role;
}Role枚举
public enum Role {USER, ADMIN
}JwtConfig配置
Configuration
public class JwtConfig {Value(${ jwt.secret})private String secret;Value(${ jwt.expiration})private Long expiration;Value(${ jwt.header})private String header;public String getSecret() {return secret;}public Long getExpiration() {return expiration;}public String getHeader() {return header;}
}JwtUtil工具类
Component
public class JwtUtil {Autowiredprivate JwtConfig config;public String generateToken(User user) {MapString, Object claims new HashMap();claims.put(id, user.getId());claims.put(username, user.getUsername());claims.put(role, user.getRole());claims.put(iat, new Date());claims.put(exp, new Date(System.currentTimeMillis() config.getExpiration()));return Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS256, config.getSecret().getBytes()).compact();}public boolean validateToken(String token) {try {Jwts.parser().setSigningKey(config.getSecret().getBytes()).parseClaimsJws(token);return true;} catch (Exception e) {return false;}}public Claims getTokenBody(String token) {return Jwts.parser().setSigningKey(config.getSecret().getBytes()).parseClaimsJws(token).getBody();}
}LoginController
RestController
RequestMapping(/api)
public class LoginController {Autowiredprivate JwtUtil jwtUtil;Autowiredprivate UserRepository userRepository;PostMapping(/login)public ResponseEntity? login(RequestBody LoginRequest loginRequest) {User user userRepository.findByUsername(loginRequest.getUsername()).orElseThrow(() - new BadCredentialsException(用户不存在));if (!user.getPassword().equals loginRequest.getPassword()) {throw new BadCredentialsException(密码错误);}String token jwtUtil.generateToken(user);return ResponseEntity.ok(new ApiResponse(登录成功, token));}
}
SecurityConfig
Configuration
EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers(/api/login).permitAll().anyRequest().authenticated().and().addFilterBefore(new JwtAuthenticationFilter(), BasicAuthenticationFilter.class);}
}
JwtAuthenticationFilter
public class JwtAuthenticationFilter extends OncePerRequestFilter {Autowiredprivate JwtUtil jwtUtil;Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException {String header request.getHeader(Authorization);if (header ! null header.startsWith(Bearer )) {String token header.substring(7);if (jwtUtil.validateToken(token)) {Claims claims jwtUtil.getTokenBody(token);UsernamePasswordAuthenticationToken authentication new UsernamePasswordAuthenticationToken(claims.getSubject(), null, getAuthorities((ListString) claims.get(role)));SecurityContextHolder.getContext().setAuthentication(authentication);} else {response.setStatus(HttpServletResponse.SC_FORBIDDEN);return;}}filterChain.doFilter(request, response);}private Collection? extends GrantedAuthority getAuthorities(ListString roles) {return roles.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());}
}3. 实战
实战中的Demo测试如下 以下代码用于实战中的讲解代码来源https://gitee.com/zhijiantianya/ruoyi-vue-pro
uniapp中封装独特的request请求
import store from /store
import config from /config
import { getAccessToken } from /utils/auth
import errorCode from /utils/errorCode
import { toast, showConfirm, tansParams } from /utils/commonlet timeout 10000
const baseUrl config.baseUrl config.baseApi;const request config {// 是否需要设置 tokenconst isToken (config.headers || {}).isToken falseconfig.header config.header || {}if (getAccessToken() !isToken) {config.header[Authorization] Bearer getAccessToken()}// 设置租户 TODO 芋艿强制 1 先config.header[tenant-id] 1;// get请求映射params参数if (config.params) {let url config.url ? tansParams(config.params)url url.slice(0, -1)config.url url}return new Promise((resolve, reject) {uni.request({method: config.method || get,timeout: config.timeout || timeout,url: config.baseUrl || baseUrl config.url,data: config.data,// header: config.header,header: config.header,dataType: json}).then(response {let [error, res] responseif (error) {toast(后端接口连接异常)reject(后端接口连接异常)return}const code res.data.code || 200const msg errorCode[code] || res.data.msg || errorCode[default]if (code 401) {showConfirm(登录状态已过期您可以继续留在该页面或者重新登录?).then(res {if (res.confirm) {store.dispatch(LogOut).then(res {uni.reLaunch({ url: /pages/login })})}})reject(无效的会话或者会话已过期请重新登录。)} else if (code 500) {toast(msg)reject(500)} else if (code ! 200) {toast(msg)reject(code)}resolve(res.data)}).catch(error {let { message } errorif (message Network Error) {message 后端接口连接异常} else if (message.includes(timeout)) {message 系统接口请求超时} else if (message.includes(Request failed with status code)) {message 系统接口 message.substr(message.length - 3) 异常}toast(message)reject(error)})})
}export default request其中token都是存放本地
const AccessTokenKey ACCESS_TOKEN
const RefreshTokenKey REFRESH_TOKEN// Token 相关 export function getAccessToken() {return uni.getStorageSync(AccessTokenKey)
}export function getRefreshToken() {return uni.getStorageSync(RefreshTokenKey)
}export function setToken(token) {uni.setStorageSync(AccessTokenKey, token.accessToken)uni.setStorageSync(RefreshTokenKey, token.refreshToken)
}export function removeToken() {uni.removeStorageSync(AccessTokenKey)uni.removeStorageSync(RefreshTokenKey)
}后续只需要发送给后端即可
再说说前段也同理
制作一个Jwt的格式
import { useCache, CACHE_KEY } from /hooks/web/useCache
import { TokenType } from /api/login/types
import { decrypt, encrypt } from /utils/jsencryptconst { wsCache } useCache()const AccessTokenKey ACCESS_TOKEN
const RefreshTokenKey REFRESH_TOKEN// 获取token
export const getAccessToken () {// 此处与TokenKey相同此写法解决初始化时Cookies中不存在TokenKey报错return wsCache.get(AccessTokenKey) ? wsCache.get(AccessTokenKey) : wsCache.get(ACCESS_TOKEN)
}// 刷新token
export const getRefreshToken () {return wsCache.get(RefreshTokenKey)
}// 设置token
export const setToken (token: TokenType) {wsCache.set(RefreshTokenKey, token.refreshToken)wsCache.set(AccessTokenKey, token.accessToken)
}// 删除token
export const removeToken () {wsCache.delete(AccessTokenKey)wsCache.delete(RefreshTokenKey)
}/** 格式化tokenjwt格式 */
export const formatToken (token: string): string {return Bearer token
}后端Java的token只需校验即可