PO:持久化对象,一个PO对象对应一张表里面的一条记录。全部对应
VO:View视图对象,用来在页面中展示数据的,页面需要哪些字段属性就添加哪些,查询出来之后赋值操作比PO对象要简单。所以提高性能。
DTO:数据传递对象,如果要查询的结果集有多张表,或者从多个表获得的数据就可以封装DTO对象,把这些表的数据全部封装到一起,形成一个对象。
POJO:中间形态,可以在PO,VO,DTO之间互相转换。
POJO在保存数据,PO
POJO在表示层,VO
POJO数据传递,DTO
package com.xxx.app.controller;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.xxx.common.core.domain.AjaxResult;
import com.xxx.common.core.domain.entity.SysMenu;
import com.xxx.common.core.domain.entity.SysUser;
import com.xxx.common.core.domain.model.LoginBody;
import com.xxx.common.utils.SecurityUtils;
import com.xxx.framework.web.service.SysLoginService;
import com.xxx.framework.web.service.SysPermissionService;
import com.xxx.system.service.ISysMenuService;
/**
* 登录验证
*
*/
@RestController
public class SysLoginController
{
@Autowired
private SysLoginService loginService;
@Autowired
private ISysMenuService menuService;
@Autowired
private SysPermissionService permissionService;
/**
* 登录方法
*
* @param loginBody 登录信息
* @return 结果
*/
@PostMapping("/login")
public AjaxResult login(@RequestBody LoginBody loginBody)
{
AjaxResult ajax = AjaxResult.success();
// 生成令牌
// String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
// loginBody.getUuid());
// ajax.put(Constants.TOKEN, token);
return ajax;
}
/**
* 获取用户信息
*
* @return 用户信息
*/
@GetMapping("getInfo")
public AjaxResult getInfo()
{
SysUser user = SecurityUtils.getLoginUser().getUser();
// 角色集合
Set roles = permissionService.getRolePermission(user);
// 权限集合
Set permissions = permissionService.getMenuPermission(user);
AjaxResult ajax = AjaxResult.success();
ajax.put("user", user);
ajax.put("roles", roles);
ajax.put("permissions", permissions);
return ajax;
}
/**
* 获取路由信息
*
* @return 路由信息
*/
@GetMapping("getRouters")
public AjaxResult getRouters()
{
Long userId = SecurityUtils.getUserId();
List menus = menuService.selectMenuTreeByUserId(userId);
return AjaxResult.success(menuService.buildMenus(menus));
}
}
// AjaxResult ajax = AjaxResult.success();
// String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
// loginBody.getUuid());
// ajax.put(Constants.TOKEN, token);
// return ajax;
一般流程是下面这样。
1、用户向服务器发送用户名和密码。
2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。
3、服务器向用户返回一个 session_id,写入用户的 Cookie。
4、用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。
http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+
、/
和=
,在 URL 里面有特殊含义,所以要被替换掉:=
被省略、+
替换成-
,/
替换成_
。这就是 Base64URL 算法。
客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。
此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization
字段里面。
private String createToken(Map claims) {
String token = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512,secret).compact();
return token;
}
image.png image.png
public String createToken(LoginUser loginUser)
{
String token = IdUtils.fastUUID();
loginUser.setToken(token);
setUserAgent(loginUser);
refreshToken(loginUser);
Map claims = new HashMap<>();
claims.put(Constants.LOGIN_USER_KEY, token);
return createToken(claims);
}
tokenService.getLoginUser(request);
Claims claims = parseToken(token);
private Claims parseToken(String token)
{
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}
private String getToken(HttpServletRequest request)
{
String token = request.getHeader(header);
if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
{
token = token.replace(Constants.TOKEN_PREFIX, "");
}
return token;
}
image.png
const whiteList = [];
router.beforeEach((to, from, next) => {
NProgress.start()
if (getToken
})
org.springframework.boot
spring-boot-starter-security
org.springframework.boot
spring-boot-starter-web
添加一个配置类,配置拦截的路径
@Configuration
public class SecurityConfig extends WebSecurityConfigureAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() // 表单登录
.add()
.authorizeRequests() // 认证配置
.anyRequest() // 任何请求
.authenticated(); // 需要身份验证
}
}
编写一个简单的controller测试
@RequestMapping("hello")
@RestController
public class HelloController {
@GetMapping("test")
public String test() {
return "spring security";
}
}
image.png
(1)JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
(2)JWT 不加密的情况下,不能将秘密数据写入 JWT。
(3)JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
(4)JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
(5)JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
(6)为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
@Bean
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
}
Authentication authentication = SecurityContextHolder.getContext().getAuthentication()
/**
* 获取Authentication
*/
public static Authentication getAuthentication()
{
return SecurityContextHolder.getContext().getAuthentication();
}
Authentication: 存储了认证信息,代表当前登录用户
SeucirtyContext: 上下文对象,用来获取Authentication
SecurityContextHolder: 上下文管理对象,用来在程序任何地方获取SecurityContext
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
{
return super.authenticationManagerBean();
}
@RestController
@RequestMapping("/API")
public class LoginController {
@Autowired
private AuthenticationManager authenticationManager;
@PostMapping("/login")
public String login(@RequestBody LoginParam param) {
// 生成一个包含账号密码的认证信息
Authentication token = new UsernamePasswordAuthenticationToken(param.getUsername(), param.getPassword());
// AuthenticationManager校验这个认证信息,返回一个已认证的Authentication
Authentication authentication = authenticationManager.authenticate(token);
// 将返回的Authentication存到上下文中
SecurityContextHolder.getContext().setAuthentication(authentication);
return "登录成功";
}
}
@Autowired
private PasswordEncoder passwordEncoder;
@PostMapping("/register")
public String register(@RequestBody UserParam param) {
UserEntity user = new UserEntity();
// 调用加密器将前端传递过来的密码进行加密
user.setUsername(param.getUsername()).setPassword(passwordEncoder.encode(param.getPassword()));
// 将用户实体对象添加到数据库
userService.save(user);
return "注册成功";
}
认证管理器,调用,认证方法
image.pngtry
{
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
AuthenticationContextHolder.setContext(authenticationToken);
// 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
authentication = authenticationManager.authenticate(authenticationToken);
}
@Service
public class UserDetailsServiceImpl implements UserDetailsService
{
}
@Resource
private AuthenticationManager authenticationManager;
调用这个认证方法
authenticate
SysUser user = userService.selectUserByUserName(username);
通过用户名查询用户
image.png/**
* 强散列哈希加密实现
*/
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder()
{
return new BCryptPasswordEncoder();
}
/**
* 身份认证接口
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
image.png
loadUserByUsername
SysUser user = userService.selectUserByUserName(username);
@Override
public SysUser selectUserByUserName(String userName)
{
return userMapper.selectUserByUserName(userName);
}
public SysUser selectUserByUserName(String userName);
image.png
public class LoginUser implements UserDetails
{
}
{
this.userId = userId;
this.deptId = deptId;
this.user = user;
this.permissions = permissions;
}
public UserDetails createLoginUser(SysUser user)
{
return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
}
public LoginUser(Long userId, Long deptId, SysUser user, Set permissions)
{
this.userId = userId;
this.deptId = deptId;
this.user = user;
this.permissions = permissions;
}
@JSONField(serialize = false)
@Override
public String getPassword()
{
return user.getPassword();
}
image.png image.png
private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
recordLoginInfo(loginUser.getUserId());
// 生成token
return tokenService.createToken(loginUser);
/**
* 设置用户代理信息
*
* @param loginUser 登录信息
*/
public void setUserAgent(LoginUser loginUser)
{
UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
String ip = IpUtils.getIpAddr();
loginUser.setIpaddr(ip);
loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
loginUser.setBrowser(userAgent.getBrowser().getName());
loginUser.setOs(userAgent.getOperatingSystem().getName());
}
String userKey = getTokenKey(loginUser.getToken());
redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
image.png
Map claims = new HashMap<>();
claims.put(Constants.LOGIN_USER_KEY, token);
return createToken(claims);
private String createToken(Map claims)
{
String token = Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS512, secret).compact();
return token;
}
token:
# 令牌自定义标识
header: Authorization
# 令牌密钥
secret: xxx
# 令牌有效期(默认30分钟)
expireTime: 30
return createToken(claims);
doFilterInternal
image.pnghttps://zhuanlan.zhihu.com/p/342755411?utm medium=social&utm oi=1343915562263547904
image.png image.png image.png image.png/**
* 匿名访问不鉴权注解
*
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Anonymous
{
}
PermitAllUrlProperties
image.png image.pnghttps://cloud.tencentcom/document/product/400/35244
image.png image.png image.png image.pngsudo /etc/init.d/bt default
image.png image.png image.png image.png
加群联系作者vx:xiaoda0423
仓库地址:https://github.com/webVueBlog/JavaGuideInterview